Как сохранить данные из UnsafeMutablePointer в файловой системе iOS

Я читаю данные с внешнего устройства 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)

По какой-то причине данные, хранящиеся в файлеURL, повреждаются (я думаю), и я не могу воспроизвести видеофайл. Я думаю, что я что-то не так делаю с Unsafe Swift, но я не уверен, что именно. Как я могу убедиться, что я правильно прочитал данные с устройства в память, а затем взял эти данные из памяти и сохранил их на жестком диске по адресу fileURL? Что я здесь делаю неправильно? Видео не будет воспроизводиться в AVPlayer с указанным URL-адресом файла.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
705
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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. Это приведет к проблемам, если объем данных превышает 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.

Другие вопросы по теме