调整块大小优化copyfile拷贝速度:需考虑的技术问题
关于
copyfile函数块大小设置的技术疑问 使用copyfile函数拷贝大量文件时,发现其速度始终慢于cp或Finder拷贝。此前并不知晓可设置块大小,而该参数对文件拷贝速度影响显著,现提出以下技术疑问:
- 手动设置块大小前需考虑哪些因素?
- 采用非2的幂次的块大小是否合理?
- 某些块大小(如过大的值)是否会引发错误(针对运行代码的Mac设备或源/目标设备)?
- 何时应/不应偏离默认块大小?
- 是否有方法确定给定源和目标设备的最优块大小,或至少找到比默认值性能更优的设置?
我编写了示例代码尝试测量不同块大小下的平均耗时,但不确定这是否为最佳测量方式,因为每次循环的耗时差异极大:
class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ aNotification: Notification) { let openPanel = NSOpenPanel() openPanel.runModal() let source = openPanel.urls[0] openPanel.canChooseDirectories = true openPanel.canChooseFiles = false openPanel.runModal() let destination = openPanel.urls[0].appendingPathComponent(source.lastPathComponent) let date = Date() let count = 10 for _ in 0..<count { try? FileManager.default.removeItem(at: destination) do { try copy(source: source, destination: destination) } catch { preconditionFailure(error.localizedDescription) } } print(-date.timeIntervalSinceNow / Double(count)) } func copy(source: URL, destination: URL) throws { try source.withUnsafeFileSystemRepresentation { sourcePath in try destination.withUnsafeFileSystemRepresentation { destinationPath in let state = copyfile_state_alloc() defer { copyfile_state_free(state) } // var bsize = Int32(16_777_216) var bsize = Int32(1_048_576) if copyfile_state_set(state, UInt32(COPYFILE_STATE_BSIZE), &bsize) != 0 || copyfile_state_set(state, UInt32(COPYFILE_STATE_STATUS_CB), unsafeBitCast(copyfileCallback, to: UnsafeRawPointer.self)) != 0 || copyfile_state_set(state, UInt32(COPYFILE_STATE_STATUS_CTX), unsafeBitCast(self, to: UnsafeRawPointer.self)) != 0 || copyfile(sourcePath, destinationPath, state, copyfile_flags_t(COPYFILE_ALL | COPYFILE_NOFOLLOW | COPYFILE_EXCL)) != 0 { throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno)) } } } } private let copyfileCallback: copyfile_callback_t = { what, stage, state, src, dst, ctx in if what == COPYFILE_COPY_DATA { if stage == COPYFILE_ERR { return COPYFILE_QUIT } var size: off_t = 0 copyfile_state_get(state, UInt32(COPYFILE_STATE_COPIED), &size) let appDelegate = unsafeBitCast(ctx, to: AppDelegate.self) if !appDelegate.setCopyFileProgress(Int64(size)) { return COPYFILE_QUIT } } return COPYFILE_CONTINUE } private func setCopyFileProgress(_ progress: Int64) -> Bool { return true } }
内容的提问来源于stack exchange,提问作者Nickkk
相关产品推荐
相关产品推荐

