3

我正在使用NSFileManager'senumeratorAtPath方法来计算特定目录下的文件大小。

NSString *iterDir = @"/path/to/dir/";
NSFileManager *fm = [[NSFileManager alloc] init];
NSDirectoryEnumerator *dirEnum = [fm enumeratorAtPath:iterDir];

NSString *file;
BOOL isDir;
long long fileSize = 0;
while (file = [dirEnum nextObject]) {
    @autoreleasepool {
        file = [iterDir stringByAppendingString:file];
        if ([fm fileExistsAtPath:file isDirectory:&isDir]) {
            if (!isDir) {
                NSError *error;
                NSDictionary *attributes = [fm attributesOfItemAtPath:file error:&error];
                if (!error) {
                    fileSize += [attributes[@"NSFileSize"] doubleValue];
                }
            }
        }
    }
}
NSLog(@"fileSize:%lld", fileSize);

结果是这样的:

在while循环中占用大量内存

有时像这样:

没有返回记忆

内存是干什么用的?为什么连外加@autoreleasepool都没有效果?

4

1 回答 1

1

即使替换有效的目录路径,我也无法使您的示例按提供的方式运行。您的代码有一些问题。这是您需要进行的一些更改。一个是这一行:

file = [iterDir stringByAppendingString:file];

真的应该改为:

file = [iterDir stringByAppendingPathComponent:file];

后者要安全得多,因为无论您的目录路径是否以 a 结尾,它都会正确附加路径/。(在我的情况下,您的原件失败了,因为我曾经[@"~/Desktop" stringByExpandingTildeInPath]获取我的目录路径;这会产生一个没有尾随的路径/。)

然后在你的循环中,你在error堆栈上分配一个未初始化的变量,通过引用传递它,然后询问它是否是nil. 这是一个错误的问题,因为error除非方法返回 nil (或者NO,取决于方法),否则不能保证 的值。相反,您应该询问 if attributesisnil并传递NULLfor error,因为否则您似乎对此不感兴趣。所以总结一下,改变这个:

NSError *error;
NSDictionary *attributes = [fm attributesOfItemAtPath:file error:&error];
if (!error) {

对此:

NSDictionary *attributes = [fm attributesOfItemAtPath:file error:NULL];
if (attributes != nil) {

我保证,解决第二个问题意味着您的结果将更加一致。同时,当我运行代码时,我得到的结果看起来可能是NSLog()语句中的有效值。

顺便说一句,您也可以对循环使用快速枚举。代替:

while (file = [dirEnum nextObject]) {

你可以改为使用:

for (file in dirEnum) {

现在回答你原来的问题。您分配的内存变大的原因是您的包含文件名的字符串被分配到您的@autoreleasepool指令范围之外的主自动释放池中,它们只会坐在那里直到该池清空。但是,在循环中使用自己的自动释放池仍然是一件好事。

于 2013-07-09T04:38:15.500 回答