web-dev-qa-db-fra.com

Itération dans les fichiers d'un dossier avec des dossiers imbriqués - Cocoa

J'ai besoin d'accéder à tous les fichiers d'un dossier, y compris les fichiers qui existent dans des dossiers imbriqués. Un exemple de dossier pourrait ressembler à ceci.

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

Disons que je voulais exécuter un processus sur chaque fichier dans "animaux" qui n'est pas un dossier. Quelle serait la meilleure façon de parcourir le dossier "animaux" et tous ses sous-dossiers pour accéder à chaque fichier?

Merci.

40
minimalpop

Utilisez NSDirectoryEnumerator pour énumérer récursivement les fichiers et répertoires sous le répertoire de votre choix, et demandez-lui de vous dire s'il s'agit d'un fichier ou d'un répertoire. Ce qui suit est basé sur l'exemple répertorié dans la documentation de -[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
    }
}
94
user557219

Vous pouvez peut-être utiliser quelque chose comme ceci:

+(void)openEachFileAt:(NSString*)path
{
  NSDirectoryEnumerator* enumerator = [[NSFileManager defaultManager] enumeratorAtPath:path];
  for (NSString * file in enumerator)
  {
     // 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];
    }
  }
}
25
Karl von Moor

Voici une version Swift:

func openEachFile(inDirectory path: String) {
    let subs = try! FileManager.default.subpathsOfDirectory(atPath: path)
    let totalFiles = subs.count
    print(totalFiles)
    for sub in subs {
        if sub.hasPrefix(".DS_Store") {
            //a DS_Store file
        }
        else if sub.hasSuffix(".xcassets") {
            //a xcassets file
        }
        else if (sub as NSString).substring(to: 4) == ".git" {
            //a git file
        }
        else if sub.hasSuffix(".Swift") {
            //a Swift file
        }
        else if sub.hasSuffix(".m") {
            //a objc file
        }
        else if sub.hasSuffix(".h") {
            //a header file
        }
        else {
            // some other file
        }
        let fullPath = (path as NSString).appendingPathComponent(sub)
    }
}
14
Esqarrouth

Ce code a fonctionné pour moi.

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]);
        }
    }
1
Avijit Nagare

Voici une solution utilisant -subpathsOfDirectoryAtPath:rootPath , avec les URL des fichiers et les cloches et sifflets de nullité Objective-C modernes.

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

… Et la même chose dans 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
mz2