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