ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

iOS 如何处理 GB 级大文件?从 FileHandle、分块读写到进度、取消与异常恢复

iOS 如何处理 GB 级大文件?从 FileHandle、分块读写到进度、取消与异常恢复 iOS 如何处理 GB 级大文件?从 FileHandle、分块读写到进度、取消与异常恢复在上一篇《从零设计一个 iOS 文件浏览器》中,我们讨论了 Sandbox、FileManager、UIDocumentPicker、Security-Scoped Resource,以及如何通过 FileProvider 抽象不同的文件来源。但当文件浏览器真正开始处理用户文件时,很快会遇到另一个问题:文件可能非常大。几十 KB 的文本文件和一个 15GB 的 4K 视频,在文件列表里看起来都只是一个FileItem。但对于底层 IO 来说,它们完全不是一回事。例如用户执行:15 GB Movie ↓ Copy ↓ Another Directory如果实现方式不合理,可能出现:内存瞬间上涨App 被系统终止UI 卡死无法展示进度无法取消任务复制失败留下残缺文件磁盘空间不足时无法正确恢复用户退出页面后任务状态丢失所以这一篇我们继续解决一个文件管理器迟早都会遇到的问题:iOS 应该如何安全地处理 GB 级大文件?1. 最危险的写法:一次性把整个文件读入内存假设我们需要复制一个文件。最直观的 Swift 写法可能是:letdata=tryData(contentsOf:sourceURL)trydata.write(to:destinationURL)对于一个几 KB 或几 MB 的文件,这段代码看起来没有什么问题。但是如果文件是:10 GB逻辑就变成:10 GB File ↓ Data(contentsOf:) ↓ 尝试加载大量数据到内存 ↓ Memory Pressure ↓ App 可能被系统终止这里需要建立文件类 App 非常重要的一个概念:文件大小不应该直接等于内存占用。一个 20GB 文件并不意味着我们需要 20GB 内存才能处理它。真正需要做的是:Streaming / Chunked IO。2. 什么是分块读写?思路其实非常简单。不要:10GB ↓ Memory ↓ Write而是:10GB File │ ▼ ┌────────┐ │ 1 MB │ └────────┘ ↓ Write ↓ ┌────────┐ │ 1 MB │ └────────┘ ↓ Write ↓ ... ↓ Destination假设每次只读取:1 MB那么无论文件是:100 MB 1 GB 10 GB 50 GB核心工作内存都不需要随着文件大小线性增长。这就是处理大文件最基础的原则之一。3. 使用 FileHandleSwift/Foundation 提供了:FileHandle我们可以使用它进行更加底层的文件读取和写入。一个简化的大文件复制示例:funccopyLargeFile(from sourceURL:URL,to destinationURL:URL)throws{letfileManager=FileManager.defaultfileManager.createFile(atPath:destinationURL.path,contents:nil)letreader=tryFileHandle(forReadingFrom:sourceURL)letwriter=tryFileHandle(forWritingTo:destinationURL)defer{try?reader.close()try?writer.close()}letchunkSize=1024*1024whiletrue{letdata=tryreader.read(upToCount:chunkSize)
返回列表