tl;博士
所有其他答案都关闭:)
问题
我想在这个老问题上加两分钱,因为似乎有很多答案都非常相似,但在某些情况下产生的结果非常不精确。
要了解为什么我们首先必须定义文件夹的大小。在我的理解(可能是 OP 之一)中,它是包含其所有内容的目录在卷上使用的字节数。或者,换一种说法:
如果目录将被完全删除,这是可用的空间。
我知道这个定义并不是解释问题的唯一有效方式,但我确实认为这是大多数用例归结为的原因。
错误
现有的答案都采用非常简单的方法:遍历目录内容,将(常规)文件的大小相加。这没有考虑到一些微妙之处。
- 卷上使用的空间以块而不是字节为单位递增。即使是一个字节的文件也至少使用一个块。
- 文件携带元数据(与任何数量的扩展属性一样)。这些数据必须保存在某个地方。
- HFS 部署文件系统压缩,以使用比实际长度更少的字节实际存储文件。
解决方案
所有这些原因使现有答案产生不精确的结果。所以我建议在NSFileManager 上进行这个扩展(由于长度原因,github 上的代码:Swift 4,Objective C)来解决这个问题。它也快了很多,尤其是对于包含大量文件的目录。
解决方案的核心是使用NSURL 的NSURLTotalFileAllocatedSizeKey 或NSURLFileAllocatedSizeKey 属性来检索文件大小。
测试
我还设置了a simple iOS test project,展示了解决方案之间的差异。它表明在某些情况下结果可能是完全错误的。
在测试中,我创建了一个包含 100 个小文件(范围从 0 到 800 字节)的目录。从其他答案复制的 folderSize: 方法计算出总共 21 kB,而我的 allocatedSize 方法产生 401 kB。
证明
我通过计算删除测试目录前后卷上可用字节的差异,确保allocatedSize 的结果更接近正确值。在我的测试中,差异总是完全等于allocatedSize 的结果。
请参阅 Rob Napier 的评论以了解仍有改进的空间。
性能
但还有另一个优势:在计算包含 1000 个文件的目录的大小时,在我的 iPhone 6 上,folderSize: 方法大约需要 250 毫秒,而allocatedSize 在 35 毫秒内遍历相同的层次结构。
这可能是由于使用NSFileManager 的新(ish)enumeratorAtURL:includingPropertiesForKeys:options:errorHandler: API 来遍历层次结构。该方法让您可以为要迭代的项目指定预取属性,从而减少 io。
结果
Test `folderSize` (100 test files)
size: 21 KB (21.368 bytes)
time: 0.055 s
actual bytes: 401 KB (401.408 bytes)
Test `allocatedSize` (100 test files)
size: 401 KB (401.408 bytes)
time: 0.048 s
actual bytes: 401 KB (401.408 bytes)
Test `folderSize` (1000 test files)
size: 2 MB (2.013.068 bytes)
time: 0.263 s
actual bytes: 4,1 MB (4.087.808 bytes)
Test `allocatedSize` (1000 test files)
size: 4,1 MB (4.087.808 bytes)
time: 0.034 s
actual bytes: 4,1 MB (4.087.808 bytes)