如何在iOS文件系统中存储来自UnsafeMutablePointer的数据

时间:2019-03-21 04:35:51

标签: ios swift unsafe-pointers

我正在使用第三方SDK“ sessionController”将MFi外部设备中的数据读取到缓冲区中。参见下文:

    let handle: UInt64 = self.sessionController.openFile(file.path, mode: openMode)
    if handle == 0 {
        //Error
        return
    }

    let c: UInt64 = file.size

    var bytesArray: [UInt8] = [UInt8](fileData)
    let bufferPointer: UnsafeMutablePointer<UInt8> = UnsafeMutablePointer<UInt8>.allocate(capacity: Int(c))

    bufferPointer.initialize(repeating: 0, count: Int(c))

    defer {
        bufferPointer.deinitialize(count: Int(c))
        bufferPointer.deallocate()
    }

    var sum: UInt32 = 0
    let singleSize: UInt32 = 8 << 20

    while sum < c {
        let read = self.sessionController.readFile(handle, data: bufferPointer, len: singleSize)
        if read == 0 {
            //There was an error
            return
        }
        sum += read
    }

    let newPointer : UnsafeRawPointer = UnsafeRawPointer(bufferPointer)

    fileURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent("test.MOV")

    fileData = Data(bytes: newPointer, count: Int(c))

    try! fileData.write(to: fileURL)

    //Now use this fileURL to watch video in an AVPlayer... 
    //AVPlayer(init: fileURL)

由于某种原因,存储在fileURL上的数据已损坏(我认为),并且无法播放视频文件。我认为我使用Unsafe Swift无法正确执行操作,但不确定如何执行。如何确保已将设备中的数据正确读取到内存中,然后从内存中获取数据并将其存储在文件URL上的硬盘上?我在这里做错了什么?给定fileURL,视频将无法在AVPlayer中播放。

1 个答案:

答案 0 :(得分:1)

主要错误在这里:

let read = self.sessionController.readFile(handle, data: bufferPointer, len: singleSize)

如果读取多个块,则第二次读取和所有后续读取将覆盖先前读取的数据。所以应该是

let read = self.sessionController.readFile(handle, data: bufferPointer + sum, len: singleSize)

还请注意,文件大小定义为UInt64,但是变量sum(保存到目前为止读取的字节总数)是UInt32。如果数据量超过4GB,将导致问题。

但是通常我会避免将完整的数据读入内存缓冲区。您已经分批读取,因此可以将数据立即写入目标文件。看起来像这样:

// Output file:
let fileURL = ...
let fileHandle = try FileHandle(forWritingTo: fileURL)
defer { fileHandle.closeFile() }

// Buffer:
let bufferSize = 1024 * 1024 // Choose some buffer size
var buffer = Data(count: bufferSize)

// Read/write loop:
let fileSize: UInt64 = file.size
var remainingToRead = fileSize
while remainingToRead > 0 {
    let read = buffer.withUnsafeMutableBytes { bufferPointer in
        self.sessionController.readFile(handle, data: bufferPointer, len: UInt32(min(remainingToRead, UInt64(bufferSize))))
    }
    if read == 0 {
        return // Read error 
    }
    remainingToRead -= UInt64(read)
    fileHandle.write(buffer)
}

还请注意,将数据直接读取到Data值中,而不是将其读取到分配的内存中,然后将其复制到另一个Data中。