2009-08-14 6 views
6

En ce moment je suis en utilisant ce code pour obtenir la taille d'un dossier:Un moyen facile d'obtenir la taille du dossier (ObjC/Cocoa)?

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]; 

Le problème est que sa très innacurate. Il ajoute quelques mégaoctets ou déduit quelques mégaoctets de la taille réelle. Par exemple j'ai obtenu la taille de fichier d'un paquet .app et cette méthode a rapporté 16.2MB, alors que la chose réelle est 15.8.

Quelle est la meilleure façon d'obtenir la taille d'un dossier?

Remerciements

+0

Toute personne qui utilise cette sous sandbox? :-) –

Répondre

5

Je devais le faire aujourd'hui moi-même, et j'ai trouvé que le code dans this post on the Cocoa-dev list est super rapide et correspond à ce que Finder dit à l'octet. (n'oubliez pas de OU dans l'indicateur kFSCatInfoRsrcSizes pour obtenir les tailles de fork de ressources, aussi!)

Si vous avez besoin de plus d'explications sur comment l'utiliser, il suffit de laisser un commentaire et je vais éditer ce post. =)

+0

Merci, quel est un bon moyen de convertir un NSString contenant un chemin vers un FSRef? Merci – indragie

+0

Vous venez de répondre à votre question. =) –

+0

@Dave, ce lien est cassé, pourriez-vous le mettre à jour ou placer le code pour répondre? – Igor

1

C'est typiquement ainsi que cela est fait. 2 possibilités:

  1. Vérifiez vos routines de conversion octets -> mégaoctets. Aussi, voulez-vous des mégaoctets ou des mebibytes? (Cela dépend probablement de ce que vous le comparez.)

  2. Essayez de passer NO pour le paramètre traverseLink. Il pourrait très bien y avoir un lien symbolique dans le bundle pointant vers quelque chose d'autre que la routine que vous le comparez ne sera pas prise en compte. Vous compterez deux fois quelque chose dans le paquet, ou vous inclurez quelque chose en dehors du paquet (probablement le premier).

4

La documentation pour fileSize indique qu'il n'inclut pas la taille d'une branche de ressources. Vous devrez peut-être utiliser le Carbon File Manager API pour calculer de manière fiable les tailles de répertoires.

+0

Ah oui, c'est une autre possibilité. J'ai oublié cela. – kperryua

2

Je voulais juste appuyer la suggestion de Dave DeLong sur le post sur Cocoa-dev, mais ajouter une note d'avertissement pour être sûr de lire tous les messages dans le fil. Il y en a un par Rosyna qui mérite particulièrement d'être noté. Dans mon cas, j'ai suivi ce conseil (en changeant le nombre maximum d'objets par aller chercher à 40) et j'ai vu un saut de vitesse ainsi que la fin d'un mauvais bug.

+1

Il serait peut-être préférable d'ajouter ceci comme commentaire à sa réponse afin qu'elles restent liées même si leurs positions sur la page changent. –

+0

J'ai des problèmes avec la méthode de Dave DeLong. J'utilise ce code pour convertir mon NSString en un FSRef: FSRef f; \t \t OSStatus os_status = FSPathMakeRef ((const UInt8 *) [filePath fileSystemRepresentation], & f, NULL); \t \t si (os_status == noErr) { \t \t \t NSLog (@ "Success"); \t \t} Et puis je tente d'exécuter la méthode: [auto fastFolderSizeAtFSRef: f]; Cependant, je reçois l'erreur "type incompatible pour l'argument 1 de 'fastFolderSize'" Des idées? Merci – indragie

2

Je sais que c'est un vieux sujet. Mais pour tout le monde là-bas chercher des réponses sur la façon de ce faire,

[[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]; 
     } 

Il utilisera terminal pour déterminer une taille pour les dossiers en octets. Et il utilisera Cocoa construit dans NSFileManager pour obtenir la taille des fichiers. C'est très rapide et obtient la taille exacte indiquée par le chercheur.

+0

alors que cela fonctionnera certainement, vous avez le coup de performance de la création d'un autre processus (qui peut être assez cher), ou en utilisant NSFileManager, qui n'inclut pas de fourches de ressources lors du calcul des tailles. –

1

Ce code est en tant qu'extension (catégorie) de la classe NSFileManager. Il résume les tailles de tout le contenu du dossier. Notez que le traitement des erreurs pourrait être amélioré.

@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 
0

espère que cela aidera

- (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; 
} 
Questions connexes