Проблема с памятью при преобразовании большого пути к видеофайлу в NSData. Как использовать InputStream/FileHandle для решения этой проблемы?

У меня есть видео большого размера, сохраненное в папке с документами. Я хочу получить это видео и удалить первые 5 байтов. Для больших видеофайлов размером более 300 МБ использование [NSData(contentsOf: videoURL)] вызывает ошибку проблемы с памятью.

Я прошел через Swift: загрузка большого видеофайла ( более 700 МБ) в память и обнаружили, что нам нужно использовать [InputStream] и [OutputStream] или [NSFileHandle] для больших файлов. Как это использовать?

Пример кода приведен ниже:

   let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
   let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
   let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
   if let dirPath = paths.first{
      let videoURL = URL(fileURLWithPath: dirPath).appendingPathComponent(filePath)
          do {
                let videoData = try NSData(contentsOf: videoURL)
                let mutabledata = videoData.mutableCopy() as! NSMutableData
                mutabledata.replaceBytes(in: NSRange(location: 0, length: 5), withBytes: nil, length: 0)
   }catch {
       print("Error Writing video: \(error)")
   }

person Sona    schedule 23.09.2019    source источник
comment
Вероятно, трата времени на чтение всего файла, если вы хотите заменить 5 байтов. Возможно, вы можете использовать функции FileHandler, такие как , seek и write?   -  person netigger    schedule 23.09.2019
comment
@netigger Спасибо! Как написать в FileHandler, чтобы сделать то же самое?   -  person Sona    schedule 23.09.2019
comment
@netigger Это устарело?   -  person Sona    schedule 24.09.2019
comment
О, я не заметил :|   -  person netigger    schedule 24.09.2019
comment
@netigger Как использовать InputStream и OutputStream, чтобы сделать то же самое. Я застрял в этом разделе, много искал, но не нашел решения.   -  person Sona    schedule 24.09.2019
comment
Проверьте мой обновленный ответ, который сработал для меня (измените содержимое файла на месте).   -  person netigger    schedule 24.09.2019


Ответы (2)


Это работает для меня для изменения первых 4 байтов, и я не получаю предупреждений об устаревании.

let input = FileHandle(forWritingAtPath: "/tmp/test.in")!
input.write("12345".data(using: .utf8)!)
person netigger    schedule 24.09.2019
comment
Является ли этот размер реальным файлом data.count? Если это так, это приводит к сбою моего приложения (проблема с памятью) при вводе. - person Sona; 24.09.2019
comment
Это запишет эти конкретные данные в приемник, верно? @netigger - person Sona; 25.09.2019
comment
Да и заменить то, что было изначально - person netigger; 25.09.2019
comment
Чтение в EOF вызывает сбой для видео размером 400 МБ. - person Sona; 25.09.2019
comment
Что именно ты делаешь? Я пытался сам изменить первые 5 байтов файла размером 400 МБ, и это прекрасно работает. - person netigger; 25.09.2019
comment
Как я уже сказал, я хочу открыть файл (файл .mp4), сохраненный в каталоге документов приложения, и удалить его первые 5 байтов. Затем мне нужно сохранить этот обновленный файл (как .mp4) в каталоге приложения. - person Sona; 25.09.2019
comment
Я знаю, что вы так сказали, но код, который я написал выше, не дает вам сбой? Или что глючит? - person netigger; 25.09.2019
comment
Давайте продолжим обсуждение в чате. - person Sona; 25.09.2019

Решил эту проблему с помощью InputStream/OutputStream.

Я использовал InputStream для чтения видео, удалил его первые 5 байтов с помощью метода dropFirst() массива и сохранил новые данные с помощью OutputStream.write().

Образец кода:

func read(stream : InpuStream){
        let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: totalLength)
        while stream.hasBytesAvailable {
            let length = self.inputStream.read(buffer, maxLength: totalLength)
            if(length == totalLength){
                let array = Array(UnsafeBufferPointer(start: buffer, count: totalLength))
                var newArray: [UInt8] = []
                newArray = [UInt8](array.dropFirst(5))
            }
    }
    func write(){
        let data = Data(_: newArray)
        data.withUnsafeBytes({ (rawBufferPointer: UnsafeRawBufferPointer) -> Int in
            let bufferPointer = rawBufferPointer.bindMemory(to: UInt8.self)
            return self.outputStream.write(bufferPointer.baseAddress!, maxLength: data.count)
        })
    }
person Sona    schedule 26.09.2019