iOS开发获取磁盘可用空间大于总空间的代码问题排查
问题原因
- 核心问题是容量统计口径不匹配
volumeTotalCapacityKey返回的是磁盘卷总物理容量中,扣除系统固定预留分区后的用户可用总容量,计算时不包含系统标记为可清理(purgeable)的存储空间。volumeAvailableCapacityForImportantUsageKey是iOS 13+新增属性,返回的是系统判断可分配给App重要任务使用的最大空间,除了当前真实空闲空间,还包含所有可清理的缓存、临时文件、其他App的可purgeable空间,这部分额外可腾退的空间没有被计入volumeTotalCapacityKey的统计结果,就会出现可用空间大于你统计的总容量的问题。 - 第二个潜在问题是类型转换溢出:
volumeTotalCapacity的类型为Int?,部分老旧系统/架构下如果容量超出32位Int最大值,会返回负数,强制转成UInt64后会变成极小值,进一步放大free大于total的问题。 - 额外说明:如果你的需求是统计App自身占用的磁盘空间,上述代码逻辑完全错误,你统计的是整个手机磁盘的卷容量,不是App沙盒的占用大小,需要遍历沙盒目录累加所有文件大小才能得到App自身的占用空间。
修复后的正确代码
如果是要获取整个磁盘的总容量/可用容量,统一统计口径即可:
// 总容量(用户可用总容量,和普通可用空间统计口径对齐) func totalDiskSpaceInBytes() -> UInt64 { guard let volumeURL = URL(fileURLWithPath: NSHomeDirectory() as String).volumeURL else { return 0 } do { let values = try volumeURL.resourceValues(forKeys: [.volumeTotalCapacityKey]) guard let capacity = values.volumeTotalCapacity.map(Int64.init) else { return 0 } return UInt64(capacity) } catch { return 0 } } // 普通可用容量(不含可清理空间,和总容量统计口径对齐) func freeDiskSpaceInBytes() -> UInt64 { guard let volumeURL = URL(fileURLWithPath: NSHomeDirectory() as String).volumeURL else { return 0 } do { let values = try volumeURL.resourceValues(forKeys: [.volumeAvailableCapacityKey]) guard let capacity = values.volumeAvailableCapacity.map(Int64.init) else { return 0 } return UInt64(capacity) } catch { return 0 } } // 若确实需要获取包含可清理空间的最大可用容量,总容量要对应换成volumeUsableCapacityKey对齐统计口径 func totalUsableDiskSpaceInBytes() -> UInt64 { guard let volumeURL = URL(fileURLWithPath: NSHomeDirectory() as String).volumeURL else { return 0 } do { let values = try volumeURL.resourceValues(forKeys: [.volumeUsableCapacityKey]) guard let capacity = values.volumeUsableCapacity else { return 0 } return UInt64(capacity) } catch { return 0 } }
内容的提问来源于stack exchange,提问作者Tomáš Černý
相关产品推荐
相关产品推荐

