3 回答
TA贡献1836条经验 获得超13个赞
tl; dr
所有其他答案都关闭了:)
问题
我想在这个老问题上加上两分钱,因为似乎有很多答案都非常相似,但在某些情况下得出的结果却非常不准确。
要了解为什么我们首先必须定义文件夹的大小。以我的理解(可能是OP之一),它是目录(包括其所有内容)在卷上使用的字节数。或者,换一种说法:
如果目录将被完全删除,则该空间变为可用。
我知道,此定义不是解释问题的唯一有效方法,但我确实认为这是大多数用例的根源。
错误
现有的答案都采用非常简单的方法:遍历目录内容,增加(常规)文件的大小。这并没有考虑到一些微妙之处。
卷上使用的空间以块为单位递增,而不是以字节为单位递增。即使是一个字节的文件也至少使用一个块。
文件包含元数据(如任意数量的扩展属性)。此数据必须放在某处。
HFS部署文件系统压缩,以实际使用较少的字节(而不是其实际长度)存储文件。
解
所有这些原因使现有的答案产生不精确的结果。因此,我提议对此扩展NSFileManager(由于长度而在github 上的代码:Swift 4,Objective C)来解决这个问题。它的速度也相当快,特别是对于包含大量文件的目录。
该解决方案的核心是使用NSURL的NSURLTotalFileAllocatedSizeKey或NSURLFileAllocatedSizeKey性的判定来检索文件的大小。
测试
我还建立了一个简单的iOS测试项目,展示了解决方案之间的差异。它显示了在某些情况下结果可能完全错误。
在测试中,我创建了一个包含100个小文件的目录(范围从0到800字节)。folderSize:从其他答案中复制的方法总共计算出21 kB,而我的allocatedSize方法得出的结果为401 kB。
证明
allocatedSize通过计算删除测试目录之前和之后卷上可用字节的差异,我确保的结果更接近正确的值。在我的测试中,差异始终等于的结果allocatedSize。
请参阅Rob Napier的评论,以了解仍有改进的空间。
性能
但是还有另一个优点:在计算包含1000个文件的目录的大小时,在我的iPhone 6上,此folderSize:方法大约需要250毫秒,而allocatedSize在35毫秒内遍历相同的层次结构。
这可能是由于使用NSFileManager的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)
TA贡献2037条经验 获得超6个赞
为亚历克斯加油打气,您已经提供了很多帮助,现在已经编写了以下功能,可以发挥作用...
- (unsigned long long int)folderSize:(NSString *)folderPath {
NSArray *filesArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:folderPath error:nil];
NSEnumerator *filesEnumerator = [filesArray objectEnumerator];
NSString *fileName;
unsigned long long int fileSize = 0;
while (fileName = [filesEnumerator nextObject]) {
NSDictionary *fileDictionary = [[NSFileManager defaultManager] fileAttributesAtPath:[folderPath stringByAppendingPathComponent:fileName] traverseLink:YES];
fileSize += [fileDictionary fileSize];
}
return fileSize;
}
它提供了与Finder一样的确切字节数。
顺便说一句,Finder返回两个数字。一个是磁盘上的大小,另一个是实际的字节数。
例如,当我在一个文件夹中运行此代码时,它以130398的“文件大小”返回代码中。当我在Finder中签入时,它说磁盘上的大小为201KB(130,398字节)。
有点不确定此处的实际大小(201KB或130,398字节)。现在,我会安全地将限制减少一半,直到我知道这到底意味着什么...
如果有人可以向这些不同的号码添加更多信息,我将不胜感激。
干杯,
- 3 回答
- 0 关注
- 700 浏览
添加回答
举报