如何利用.volumeAvailableCapacityForImportantUsageKey报告的可用空间?
iOS 如何利用
volumeAvailableCapacityForImportantUsageKey 返回的额外可用空间 可以通过多种方式查询iOS设备的可用空间,其中volumeAvailableCapacityForImportantUsageKey会返回更高的容量值——这是因为系统允许在存储重要内容时,自动清理临时/非重要文件来腾出空间。但实际测试时,一旦写入量达到常规可用容量(比如volumeAvailableCapacityKey、NSFileManager或boost::filesystem::space.available返回的值),应用就会崩溃,报错:[general] Encountered write failure 28 No space left on device。
测试用的写入代码如下:
func writeFile(size: Measurement<UnitInformationStorage>) { deleteFile() let filename = getDocumentsDirectory().appendingPathComponent("output.txt") var megabyteOfData: [UInt8] = [] for i in 0..<1024*1024 { megabyteOfData.append(UInt8(i % 0xff)) } let data = Data(bytes: &megabyteOfData, count: megabyteOfData.count * MemoryLayout<UInt8>.stride) do { let chunks = Int(size.converted(to: UnitInformationStorage.megabytes).value) try data.write(to: filename, options: .atomicWrite) let fileHandle = try FileHandle(forWritingTo: filename) for i in 2...chunks { print("Writing \(i) chunk...") fileHandle.write(data) } try fileHandle.close() } catch { print(error) } }
问题核心
iOS不会在你写入文件时自动触发临时文件清理,你需要主动清理自身临时文件,并在遇到空间不足时给系统时间回收可释放空间,才能利用volumeAvailableCapacityForImportantUsageKey对应的额外容量。
解决方案
1. 提前获取并校验重要可用空间
在写入前,先确认要写入的文件大小不超过volumeAvailableCapacityForImportantUsageKey返回的值,避免无效操作:
func getImportantAvailableSpace() -> Measurement<UnitInformationStorage>? { let documentsDir = getDocumentsDirectory() do { let resourceValues = try documentsDir.resourceValues(forKeys: [.volumeAvailableCapacityForImportantUsageKey]) if let capacity = resourceValues.volumeAvailableCapacityForImportantUsageKey { return Measurement(value: Double(capacity), unit: UnitInformationStorage.bytes) } } catch { print("获取重要可用空间失败: \(error)") } return nil } // 调用示例 if let availableSpace = getImportantAvailableSpace(), size <= availableSpace { writeFile(size: size) } else { print("重要可用空间不足") }
2. 主动清理自身临时文件
在写入大文件前,先清理应用自身的临时文件和缓存,腾出基础空间的同时,触发系统的空间回收机制:
func cleanupLocalTempFiles() throws { // 清理临时目录文件 let tempDir = FileManager.default.temporaryDirectory for file in try FileManager.default.contentsOfDirectory(at: tempDir, includingPropertiesForKeys: nil) { try FileManager.default.removeItem(at: file) } // 清理缓存目录中可删除的文件 let cachesDir = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first! for file in try FileManager.default.contentsOfDirectory(at: cachesDir, includingPropertiesForKeys: nil) { try FileManager.default.trashItem(at: file, resultingItemURL: nil) } }
3. 写入时增加错误重试逻辑
当遇到空间不足错误时,不要直接崩溃,等待系统完成临时文件清理后重试:
func writeFile(size: Measurement<UnitInformationStorage>) { deleteFile() let filename = getDocumentsDirectory().appendingPathComponent("output.txt") var megabyteOfData: [UInt8] = [] for i in 0..<1024*1024 { megabyteOfData.append(UInt8(i % 0xff)) } let data = Data(bytes: &megabyteOfData, count: megabyteOfData.count * MemoryLayout<UInt8>.stride) do { // 先清理本地临时文件 try cleanupLocalTempFiles() let chunks = Int(size.converted(to: UnitInformationStorage.megabytes).value) try data.write(to: filename, options: .atomicWrite) let fileHandle = try FileHandle(forWritingTo: filename) for i in 2...chunks { print("Writing \(i) chunk...") do { fileHandle.write(data) } catch let error as NSError where error.code == 28 { // 遇到空间不足,等待系统清理后重试 Thread.sleep(forTimeInterval: 1.5) fileHandle.write(data) } } try fileHandle.close() } catch { print(error) } }
内容的提问来源于stack exchange,提问作者Enmaniac
相关产品推荐
相关产品推荐

