Как хранить данные из UnsafeMutablePointer в файловой системе iOS - PullRequest
1 голос
/ 21 марта 2019

Я считываю данные с внешнего устройства MFi в буфер, используя сторонний SDK "sessionController".См. Ниже:

    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, но я не уверен, что.Как я могу убедиться, что я правильно прочитал данные с устройства в память, а затем взял эти данные из памяти и сохранил их на жестком диске в fileURL?Что я здесь не так делаю?Видео не будет воспроизводиться в AVPlayer с учетом файла UL.

1 Ответ

2 голосов
/ 21 марта 2019

Основная ошибка здесь:

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

Если вы читаете несколькими порциями, то второе и все последующие чтения будут перезаписывать данные, прочитанные ранее.Так что это, вероятно, должно быть

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

Обратите также внимание, что размер файла определен как UInt64, но переменная sum (которая содержит общее количество прочитанных байтов) - UInt32,Это приведет к проблемам, если данных больше 4 ГБ.

Но обычно я бы не считывал полные данные в буфер памяти.Вы уже прочитали порциями, поэтому вы можете сразу записать данные в файл назначения.Вот как это может выглядеть:

// 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.

...