【问题标题】:Easy way to get size of folder (ObjC/Cocoa)?获取文件夹大小的简单方法(ObjC/Cocoa)?
【发布时间】:2010-11-19 12:35:06
【问题描述】:

现在我正在使用此代码来获取文件夹的大小:

NSArray *contents;
        NSEnumerator *enumerator;
        NSString *path;
        contents = [[NSFileManager defaultManager] subpathsAtPath:folderPath];
        enumerator = [contents objectEnumerator];
        while (path = [enumerator nextObject]) {
            NSDictionary *fattrib = [[NSFileManager defaultManager] fileAttributesAtPath:[folderPath stringByAppendingPathComponent:path] traverseLink:YES];
            fileSize +=[fattrib fileSize];
        }

        [contents release];
        [path release]; 

问题在于它非常不准确。它要么增加几兆字节,要么从实际大小中减去几兆字节。例如,我得到了一个 .app 包的文件大小,这个方法报告了 16.2MB,而实际是 15.8。

获取文件夹大小的最佳方法是什么?

谢谢

【问题讨论】:

  • 有人在沙盒下使用这个吗? :-)

标签: objective-c cocoa size directory nsfilemanager


【解决方案1】:

我今天需要自己做这件事,我发现this post on the Cocoa-dev list 中的代码非常快,并且与 Finder 对字节的说法相匹配。 (不要忘记在 kFSCatInfoRsrcSizes 标志中进行 OR 操作,这样您也可以获得资源分叉大小!)

如果您需要有关如何使用它的更多说明,请发表评论,我将编辑此帖子。 =)

【讨论】:

  • 谢谢,将包含路径的 NSString 转换为 FSRef 的好方法是什么?谢谢
  • 刚刚回答了您的问题。 =)
  • @Dave,此链接已损坏,您可以更新它或放置代码来回答吗?
  • @Igor 已修复,带有 archive.org 链接
  • 感谢您的快速回复!
【解决方案2】:

fileSize 的文档声明它不包括资源分叉的大小。您可能需要使用Carbon File Manager API 来可靠地计算目录大小。

【讨论】:

  • 啊,是的,这是另一种可能性。我忘记了。
【解决方案3】:

我只是想支持 Dave DeLong 关于 Cocoa-dev 上的帖子的建议,但添加一个警告说明以确保阅读线程中的所有帖子。 Rosyna 有一个特别值得注意。就我而言,我遵循了该建议(将每次提取的最大项目数更改为 40)并看到了速度的飞跃以及令人讨厌的崩溃错误的结束。

【讨论】:

  • 最好将此作为评论添加到他的答案中,这样即使他们在页面上的位置发生变化,他们也能保持相关性。
  • 我在使用 Dave DeLong 的方法时遇到了问题。我使用此代码将我的 NSString 转换为 FSRef: FSRef f; OSStatus os_status = FSPathMakeRef((const UInt8 *)[filePath fileSystemRepresentation], &f, NULL); if (os_status == noErr) { NSLog(@"Success");然后我尝试运行该方法: [self fastFolderSizeAtFSRef:f];但是我收到错误“'fastFolderSize' 的参数 1 的类型不兼容”有什么想法吗?谢谢
【解决方案4】:

希望这会有所帮助

- (unsigned long long) fastFolderSizeAtFSRef:(NSString *)theFilePath
{
unsigned long long totalSize = 0;
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL  isdirectory;
NSError *error;

if ([fileManager fileExistsAtPath:theFilePath])
{


    NSMutableArray * directoryContents = [[fileManager contentsOfDirectoryAtPath:theFilePath error:&error] mutableCopy];


    for (NSString *fileName in directoryContents)
    {
        if (([fileName rangeOfString:@".DS_Store"].location != NSNotFound) )
            continue;



            NSString *path = [theFilePath stringByAppendingPathComponent:fileName];
            if([fileManager fileExistsAtPath:path isDirectory:&isdirectory] && isdirectory  )
            {

                    totalSize =  totalSize + [self fastFolderSizeAtFSRef:path];



            }
            else
            {
                unsigned long long fileSize = [[fileManager attributesOfItemAtPath:path error:&error] fileSize];
                totalSize = totalSize + fileSize;
            }
    }
}
return totalSize;
}

【讨论】:

    【解决方案5】:

    这通常是如何完成的。 2 种可能性:

    1. 检查您的字节 -> 兆字节转换例程。另外,你想要兆字节还是兆字节? (这可能取决于您将其与什么进行比较。)

    2. 尝试为 traverseLink 参数传递 NO。捆绑包中很可能有一个符号链接指向您与之比较的例程无法解释的其他内容。您要么计算捆绑包中的某些内容两次,要么完全包含捆绑包之外的某些内容(很可能是前者)。

    【讨论】:

      【解决方案6】:

      我知道这是一个老话题。但是对于那些正在寻找如何做到这一点的答案的人来说,

      [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir];
              if (isDir) {
                  NSPipe *pipe = [NSPipe pipe];
                  NSTask *t = [[[NSTask alloc] init] autorelease];
                  [t setLaunchPath:@"/usr/bin/du"];
                  [t setArguments:[NSArray arrayWithObjects:@"-k", @"-d", @"0", path, nil]];
                  [t setStandardOutput:pipe];
                  [t setStandardError:[NSPipe pipe]];
      
                  [t launch];
      
                  [t waitUntilExit];
      
                  NSString *sizeString = [[[NSString alloc] initWithData:[[pipe fileHandleForReading] availableData] encoding:NSASCIIStringEncoding] autorelease];
                  sizeString = [[sizeString componentsSeparatedByString:@" "] objectAtIndex:0];
                  bytes = [sizeString longLongValue]*1024;
              }
              else {
                  bytes = [[[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil] fileSize];
              }
      

      它将使用终端来确定文件夹的大小(以字节为单位)。它会使用 Cocoa 内置的 NSFileManager 来获取文件的大小。它非常快,并且可以得到 finder 报告的确切大小。

      【讨论】:

      • 虽然这肯定行得通,但创建另一个进程(可能会非常昂贵)或使用NSFileManager(在计算大小时不包括资源分叉)会对性能造成影响。跨度>
      【解决方案7】:

      此代码作为 NSFileManager 类的扩展(类别)。它汇总了所有文件夹内容的大小。 请注意,可以增强错误处理。

       @interface NSFileManager(Util)
      
              - (NSNumber *)sizeForFolderAtPath:(NSString *) source error:(NSError **)error;
      
          @end
      
          @implementation NSFileManager(Util)
      
              - (NSNumber *)sizeForFolderAtPath:(NSString *) source error:(NSError **)error
              {
                  NSArray * contents;
                  unsigned long long size = 0;
                  NSEnumerator * enumerator;
                  NSString * path;
                  BOOL isDirectory;
      
                  // Determine Paths to Add 
                  if ([self fileExistsAtPath:source isDirectory:&isDirectory] && isDirectory) 
                  { 
                      contents = [self subpathsAtPath:source]; 
                  } 
                  else 
                  { 
                      contents = [NSArray array];
                  }
                  // Add Size Of All Paths 
                  enumerator = [contents objectEnumerator]; 
                  while (path = [enumerator nextObject]) 
                  {
                      NSDictionary * fattrs = [self attributesOfItemAtPath: [ source stringByAppendingPathComponent:path ] error:error];
                      size += [[fattrs objectForKey:NSFileSize] unsignedLongLongValue]; 
                  }
                  // Return Total Size in Bytes 
      
                  return [ NSNumber numberWithUnsignedLongLong:size];
              }
      
              @end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-01
        相关资源
        最近更新 更多