2011-04-21 7 views
38

Necesito acceder a todos los archivos de una carpeta, incluido el archivo que existe dentro de las carpetas anidadas. Una carpeta de ejemplo podría verse así.Iterar a través de archivos en una carpeta con carpetas anidadas - Cocoa

animals/ 
-k.txt 
-d.jpg 
cat/ 
    -r.txt 
    -z.jpg 
    tiger/ 
     -a.jpg 
     -p.pdf 
dog/ 
    -n.txt 
    -f.jpg 
-p.pdf 

Digamos que quería ejecutar un proceso en cada archivo dentro de "animales" que no es una carpeta. ¿Cuál sería la mejor manera de recorrer la carpeta "animals" y todas sus subcarpetas para acceder a cada archivo?

Gracias.

+1

Función recursiva que se llama a sí misma para cada carpeta y busca el archivo – Guidhouse

Respuesta

85

Uso NSDirectoryEnumerator enumerar de forma recursiva archivos y directorios bajo el directorio que desea, y pedirle que le diga si se trata de un archivo o directorio. El siguiente se basa en el ejemplo que aparece en la documentación para -[NSFileManager enumeratorAtURL:includingPropertiesForKeys:options:errorHandler:]:

NSFileManager *fileManager = [NSFileManager defaultManager]; 
NSURL *directoryURL = … // URL pointing to the directory you want to browse 
NSArray *keys = [NSArray arrayWithObject:NSURLIsDirectoryKey]; 

NSDirectoryEnumerator *enumerator = [fileManager 
    enumeratorAtURL:directoryURL 
    includingPropertiesForKeys:keys 
    options:0 
    errorHandler:^(NSURL *url, NSError *error) { 
     // Handle the error. 
     // Return YES if the enumeration should continue after the error. 
     return YES; 
}]; 

for (NSURL *url in enumerator) { 
    NSError *error; 
    NSNumber *isDirectory = nil; 
    if (! [url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:&error]) { 
     // handle error 
    } 
    else if (! [isDirectory boolValue]) { 
     // No error and it’s not a directory; do something with the file 
    } 
} 
+2

Me ahorró una buena cantidad de tiempo :) – GoodSp33d

+3

Creo que la manera más limpia de iniciar NSFileManager es usar el método singleton [NSFileManager defaultManager] En lugar de [[[NSFileManager alloc] init] liberación automática] – ProblemSlover

+0

¡Respuesta perfecta ...! Gracias. –

25

Tal vez se puede usar algo como esto:

+(void)openEachFileAt:(NSString*)path 
{ 
    NSString* file; 
    NSDirectoryEnumerator* enumerator = [[NSFileManager defaultManager] enumeratorAtPath:path]; 
    while (file = [enumerator nextObject]) 
    { 
    // check if it's a directory 
    BOOL isDirectory = NO; 
    NSString* fullPath = [path stringByAppendingPathComponent:file]; 
    [[NSFileManager defaultManager] fileExistsAtPath:fullPath 
             isDirectory: &isDirectory]; 
    if (!isDirectory) 
    { 
     // open your file (fullPath)… 
    } 
    else 
    { 
     [self openEachFileAt: fullPath]; 
    } 
    } 
} 
+1

¿Funcionará correctamente? La enumeración es profunda, por lo que también mostrará los contenidos de todos los subdirectorios. Realmente me gustaría utilizar esto, pero ¿hay alguna manera de limitar el enumerador al directorio actual? – EtienneSky

+0

Solo porque acabo de ver este comentario: si no quieres los subdirectores simplemente no llames [self openEachFileAt: file]; de nuevo. – david

+0

Extremadamente tarde pero solo quería agradecerle por resolver mi mayor dolor de cabeza. – Robert

12

Aquí es una versión rápida:

func openEachFileAt(path: String) { 
    var file: String 

    var subs = NSFileManager.defaultManager().subpathsOfDirectoryAtPath(path, error: nil) as! [String] 
    var totalFiles = subs.count 
    println(totalFiles) 
    for sub in subs { 

     if sub.rangeOfString(".DS_Store") != nil { 
      //a DS_Store file 
     } else if sub.rangeOfString(".xcassets") != nil { 
      //a xcassets file 
     } else if (sub as NSString).substringWithRange(NSRange(location: 0, length: 4)) == ".git" { 
      //a git file 
     } else if sub.pathExtension == "swift" { 
      //a swift file 
     } else if sub.pathExtension == "m" { 
      //a objc file 
     } else if sub.pathExtension == "h" { 
      //a header file 
     } else { 

     } 
     var fullPath = path.stringByAppendingPathComponent(sub) 
    } 
} 
+0

¿Quién pidió Swift? –

+5

Estaba buscando y no pude encontrarlo, entonces tuve que resolverlo. Podría haber hecho una nueva pregunta y pegar mi respuesta o simplemente pegar mi respuesta aquí. ¿Cuál es mejor? – Esqarrouth

+0

Deje esta respuesta aquí y cree una pregunta más y pegue la respuesta. Recuerde etiquetar velozmente no obj-c o cocoa. –

0

Aquí es una solución utilizando -subpathsOfDirectoryAtPath:rootPath, con direcciones URL de archivos y modernas campanas nulabilidad Objective-C & silbatos.

typedef void (^FileEnumerationBlock)(NSURL *_Nonnull fileURL); 

@interface NSFileManager (Extensions) 

- (void)enumerateWithRootDirectoryURL:(nonnull NSURL *)rootURL 
          fileHandler:(FileEnumerationBlock _Nonnull)fileHandler 
           error:(NSError *_Nullable *_Nullable)error; 

@end 

@implementation NSFileManager (Extensions) 

- (void)enumerateWithRootDirectoryURL:(NSURL *)rootURL 
          fileHandler:(FileEnumerationBlock)fileHandler 
           error:(NSError **)error { 
    NSString *rootPath = rootURL.path; 
    NSAssert(rootPath != nil, @"Invalid root URL %@ (nil path)", rootURL); 

    NSArray *subs = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:rootPath 
                     error:error]; 

    if (!subs) { 
     return; 
    } 

    for (NSString *sub in subs) { 
     fileHandler([rootURL URLByAppendingPathComponent:sub]); 
    } 
} 

@end 

... y lo mismo en Swift:

func enumerate(rootDirectoryURL rootURL: NSURL, fileHandler:(URL:NSURL)->Void) throws { 
    guard let rootPath = rootURL.path else { 
     preconditionFailure("Invalid root URL: \(rootURL)") 
    } 

    let subs = try NSFileManager.defaultManager().subpathsOfDirectoryAtPath(rootPath) 
    for sub in subs { 
     fileHandler(URL: rootURL.URLByAppendingPathComponent(sub)) 
    } 
} 
0

Este código trabajó para mí.

NSMutableString *allHash; 

    -(NSString*)getIterate:(NSString*)path { 

     allHash = [NSMutableString stringWithString:@""]; 

     NSDirectoryEnumerator *de= [[NSFileManager defaultManager] enumeratorAtPath:path]; 
     NSString *file; 
     BOOL isDirectory; 

     for(file in de) 
     { 

      //first check if it's a file 
      NSString* fullPath = [NSString stringWithFormat:@"%@/%@",path,file]; 

      BOOL fileExistsAtPath = [[NSFileManager defaultManager] fileExistsAtPath:fullPath isDirectory:&isDirectory]; 
      NSLog(@"Check=>%d",fileExistsAtPath); 

      if (!isDirectory) //its a file 
      { 
       //Do with filepath 
      } 
      else{ //it's a folder, so recurse 
       [self enumerateFolder:fullPath]; 
      } 
     } 

     return allHash; 


    } 

    -(void) enumerateFolder:(NSString*)fileName 
    { 

     NSDirectoryEnumerator *de= [[NSFileManager defaultManager] enumeratorAtPath:fileName]; 
     NSString* file; 
     BOOL isDirectory; 

     for(file in de) 
     { 
      //first check if it's a file 
      BOOL fileExistsAtPath = [[NSFileManager defaultManager] fileExistsAtPath:file isDirectory:&isDirectory]; 

      if (fileExistsAtPath) { 
       if (!isDirectory) //its a file 
       { 
        //Do with file 
       } 
       else{ //it's a folder, so recurse 

        [self enumerateFolder:file]; 
       } 
      } 
      else printf("\nenumeratefolder No file at path %s",[file UTF8String]); 
     } 
    } 
Cuestiones relacionadas