
macOS 开发 - 获取与 Finder 一致的文件大小
在 macOS 开发中,你是否遇到过应用显示的文件大小与 Finder 不一致的困扰?这个看似简单的问题背后其实暗藏小玄机🙃。本文将和大家分享在开发 Zipic 时遇到的这个小问题及其解决过程,希望能帮助遇到类似问题的开发者少走些弯路 🚀
在开发 macOS 应用时,文件大小的显示是一个看似简单但实际暗藏玄机的问题。最近在开发我的文件压缩工具 Zipic 时就遇到了这个有趣的"坑" 🕳️,用户反馈说应用显示的文件大小与 Finder 中看到的不一致,这让他们对软件的准确性产生了怀疑。作为一个追求极致体验的开发者,我当然要把这个问题解决好!让我们一起深入了解如何在 macOS 应用中获取与 Finder 一致的文件大小显示吧 🚀
问题初现 🤔
最初的实现中,我是这样获取文件大小的:
1let fileSize = try FileManager.default.attributesOfItem(atPath: url.path)[.size] as? Int ?? 0
然后通过简单的 1024 进制换算来显示大小:
1 2 3 4 5 6 7 8 9 10 11 12 13 14extension Int { var readableFileSize: String { let units = ["B", "KB", "MB", "GB", "TB"] var size = Double(self) var unitIndex = 0 while size >= 1024 && unitIndex < units.count - 1 { size /= 1024 unitIndex += 1 } return String(format: "%.2f %@", size, units[unitIndex]) } }
看起来没什么问题对吧?但实际运行后发现显示的大小总是和 Finder 中看到的有一点点差异,虽然差异不大,但作为一个细节控,这让我很在意 😅
探究文件大小的本质 📚
为什么会出现这种差异呢?这就要从文件系统说起了。
在文件系统中,文件大小实际上有两个概念:
- 逻辑大小:文件实际内容的大小
- 物理大小:文件在磁盘上实际占用的空间大小
两者的区别主要来自以下几个因素:
- 磁盘块大小(通常是 4KB)的对齐
- 文件系统的额外开销(元数据、扩展属性等)
- 文件系统的特性(如压缩、稀疏文件等)
而 Finder 在显示文件大小时,默认显示的是文件的逻辑大小。当你在 Finder 中按下 ⌘+I 查看文件信息时,会同时看到"大小"(逻辑大小)和"占用空间"(物理大小)两个值。
优雅的解决方案 ✨
经过研究,我找到了一个完美的解决方案。Swift 提供了 ByteCountFormatter 这个强大的格式化工具,配合 URL 的 resourceValues 属性,我们可以非常优雅地解决这个问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25extension Int64 { var bytesDescription: String { let formatter = ByteCountFormatter() formatter.countStyle = .file return formatter.string(fromByteCount: self) } } extension URL { /// 获取 Finder 风格的文件大小字符串 var finderFileSize: String { return self.fileSize.bytesDescription } /// 获取文件大小的原始字节数 var fileSize: Int64 { do { let resourceValues = try self.resourceValues(forKeys: [.totalFileSizeKey]) return Int64(resourceValues.totalFileSize ?? 0) } catch { print("Error getting file size: \(error)") return 0 } } }
- 使用
.totalFileSizeKey而不是.totalFileAllocatedSizeKey,这样获取的就是文件的逻辑大小,与 Finder 保持一致 ByteCountFormatter的.file样式完美匹配了 Finder 的显示方式- 通过扩展 URL 实现计算属性,使用起来非常方便
使用示例:
1 2let fileURL = URL(fileURLWithPath: "/path/to/your/file") print(fileURL.finderFileSize) // 输出与 Finder 一致的大小显示
扩展知识 🎯
ByteCountFormatter 的其他技巧
ByteCountFormatter 还有一些有趣的配置选项:
1 2 3 4 5let formatter = ByteCountFormatter() formatter.countStyle = .file // 文件大小风格 formatter.allowedUnits = .all // 允许使用所有单位 formatter.includesUnit = true // 包含单位 formatter.isAdaptive = true // 自适应显示
resourceValues 的其他实用属性
URL 的 resourceValues 还提供了许多其他有用的属性:
1 2 3 4 5 6try url.resourceValues(forKeys: [ .creationDateKey, // 创建日期 .contentModificationDateKey, // 修改日期 .fileProtectionKey, // 文件保护级别 .isDirectoryKey // 是否是目录 ])
实践建议 🎉
- 在显示文件大小时,始终使用
ByteCountFormatter而不是自己计算,这样可以确保与系统保持一致 - 需要获取文件大小时优先使用
resourceValues,它提供了更多的控制和信息 - 注意区分逻辑大小和物理大小,根据实际需求选择合适的获取方式
- 记得处理可能的错误情况,提供良好的错误提示
总结
通过这次深入研究,我们不仅解决了文件大小显示的问题,还学习到了很多文件系统的知识。细节决定成败,追求极致的用户体验永远不会错 💪
希望这篇文章能帮助你在 macOS 开发中避开这个小坑。如果你有任何问题或建议,欢迎在评论区留言讨论 🎯



