2017-01-15 50 views
0

如何在Swift/iOS中合併文件? FileManager可以移動和複製項目,但我沒有看到任何關於合併文件。我想有一些像Swift - 合併文件

FileManager.default.merge(files: [URL], to location: URL) throws

文件可能是很大的,所以我寧願避免通過在內存中他們的數據。

===這是我自己的內存合併:

let data = NSMutableData() 
files.forEach({ partLocation in 
    guard let partData = NSData(contentsOf: partLocation) else { return } 
    data.append(partData as Data) 
    do { 
    try FileManager.default.removeItem(at: partLocation) 
    } catch { 
    print("error \(error)") 
    } 
}) 
data.write(to: destination, atomically: true) 
+1

總是有做飯的選項你自己。在寫入目的地時連續讀取每個文件。 – Alexander

+1

但有沒有像「追加到目的地」的東西?如果可能的話,我想避免讀取整個文件,然後寫入以限制內存使用量 – Guig

+1

這就是爲什麼你有'FileHandle.readData(ofLength:Int)'。你可以創建一個循環,讀取類似4kb的塊,並將它們寫入輸出。使緩衝區更大將通過最小化內核上下文切換開銷來提高性能,但會使用更多內存 – Alexander

回答

1

這是我自己的解決方案(感謝@Alexander爲指導)

extension FileManager { 
    func merge(files: [URL], to destination: URL, chunkSize: Int = 1000000) throws { 
    try FileManager.default.createFile(atPath: destination.path, contents: nil, attributes: nil) 
    let writer = try FileHandle(forWritingTo: destination) 
    try files.forEach({ partLocation in 
     let reader = try FileHandle(forReadingFrom: partLocation) 
     var data = reader.readData(ofLength: chunkSize) 
     while data.count > 0 { 
     writer.write(data) 
     data = reader.readData(ofLength: chunkSize) 
     } 
     reader.closeFile() 
    }) 
    writer.closeFile() 
    } 
} 
+0

合併工作正常,任何想法如何處理合並大文件時的內存問題? – sujay

+0

chunkSize控制使用多少內存 – Guig

+0

以及我們如何在合併大文件時清除它。 – sujay

0
func merge(files: [URL], to destination: URL, chunkSize: Int = 100000000) { 
     for partLocation in files { 
      // create a stream that reads the data above 
      let stream: InputStream 
      stream = InputStream.init(url: partLocation)! 
      // begin reading 
      stream.open() 
      let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: chunkSize) 
      //   var writeData : Data = Data() 
      while stream.hasBytesAvailable { 
       let read = stream.read(buffer, maxLength: chunkSize) 

       var writeData:Data = Data() 
       writeData.append(buffer, count: read) enter code here 
       if let outputStream = OutputStream(url: destination, append: true) { 
        outputStream.open() 
        writeData.withUnsafeBytes { outputStream.write($0, maxLength: writeData.count) } 
        outputStream.close() 
        writeData.removeAll() 
       } 
      } 
      stream.close() 
      buffer.deallocate(capacity: chunkSize) 

     } 
    }