Iterating through files in a folder with nested folders – Cocoa

I need to access every file in a folder, including file that exist within nested folders. An example folder might look like this.

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

Say that I wanted to run a process on every file within “animals” that isn’t folder. What would be the best way to iterate through the folder “animals” and all of its subfolders to access every file?

  • Running a Cocoa GUI in a non-main thread
  • Get video NSData from ALAsset url iOS
  • Calculating number of seconds between two points in time, in Cocoa, even when system clock has changed mid-way
  • How to get a swift enum's associated value regardless of the enum case
  • Detect Language of NSString
  • NSString indexOf in Objective-C
  • Thanks.

    5 Solutions Collect From Internet About “Iterating through files in a folder with nested folders – Cocoa”

    Use NSDirectoryEnumerator to recursively enumerate files and directories under the directory you want, and ask it to tell you whether it is a file or directory. The following is based on the example listed at the documentation for -[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
        }
    }
    

    Maybe you can use something like this:

    +(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];
        }
      }
    }
    

    Here is a swift version:

    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)
        }
    }
    

    Here’s a solution using -subpathsOfDirectoryAtPath:rootPath, with file URLs and modern Objective-C nullability bells & whistles.

    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
    

    … and the same in 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))
        }
    }
    

    This code worked for me.

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