NSFileManager list directory contents excluding directories

10,336

Solution 1

You can go a little deeper with a directory enumerator.

How about this?

NSDirectoryEnumerator *dirEnumerator = [localFileManager enumeratorAtURL:directoryToScan includingPropertiesForKeys:[NSArray arrayWithObjects:NSURLNameKey, NSURLIsDirectoryKey,nil] options:NSDirectoryEnumerationSkipsSubdirectoryDescendants  errorHandler:nil];
NSMutableArray *theArray=[NSMutableArray array];

for (NSURL *theURL in dirEnumerator) {

    // Retrieve the file name. From NSURLNameKey, cached during the enumeration.
    NSString *fileName;
    [theURL getResourceValue:&fileName forKey:NSURLNameKey error:NULL];

    // Retrieve whether a directory. From NSURLIsDirectoryKey, also
    // cached during the enumeration.

    NSNumber *isDirectory;
    [theURL getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:NULL];


    if([isDirectory boolValue] == NO)
    {
        [theArray addObject: fileName];
    }
}

// theArray at this point contains all the filenames

Solution 2

The best options is to use enumeratorAtURL:includingPropertiesForKeys:options:errorHandler: to populate an array that excludes folders.

NSFileManager *fm = [[NSFileManager alloc] init];
NSDirectoryEnumerator *dirEnumerator = [fm enumeratorAtURL:directoryToScan
                    includingPropertiesForKeys:@[ NSURLNameKey, NSURLIsDirectoryKey ]
                    options:NSDirectoryEnumerationSkipsHiddenFiles | NSDirectoryEnumerationSkipsSubdirectoryDescendants
                    errorHandler:nil];

NSMutableArray *fileList = [NSMutableArray array];

for (NSURL *theURL in dirEnumerator) {
    NSNumber *isDirectory;
    [theURL getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:NULL];
    if (![isDirectory boolValue]) {
        [fileList addObject:theURL];
    }
}

This will give you an array of NSURL objects representing the files.

Solution 3

There's no way around getting the contents including directories and then paring them down from there, but that's not really a problem.

The NSURLs you get from the file manager will tell you if the file system object each represents is a directory, as long as you include the NSURLIsDirectoryKey item in the "properties for keys" list.

There's any number of ways to filter the array using that information after you've got it -- or by enumerating, as the other answers demonstrate.

You could add an accessor method to NSURL:

@implementation NSURL (RWIsDirectory)

- (BOOL)RWIsDirectory
{
    NSNumber * isDir;
    [self getResourceValue:&isDir forKey:NSURLIsDirectoryKey error:NULL];
    return [isDir boolValue];
}

@end

Then use a predicate:

[directoryContents filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"RWIsDirectory == NO"]];
Share:
10,336
Rainier Wolfcastle
Author by

Rainier Wolfcastle

Updated on June 15, 2022

Comments

  • Rainier Wolfcastle
    Rainier Wolfcastle almost 2 years

    Is there a way to tell the -[NSFileManager contentsOfDirectoryAtURL:includingPropertiesForKeys:options:error:] method to exclude directory names when gathering the contents of a directory?

    I have a tree view showing folders and want to show ONLY files in the table view, but I can't seem to find a key or any other way to exclude folders. I suppose I could iterate the returned array to stuff only files into a second array, which will be used as the data source, but this double-handling seems a bit dodgy.

    I also tried returning nil from the tableView:viewForTableColumn:row: method if the NSURL was a directory, but that only results in a blank row in the table, so that's no good either.

    Surely there is a way to just tell NSFileManager that I only want files?

  • Michael Dautermann
    Michael Dautermann over 10 years
    +1 to you for coming up with the exact same answer 10 seconds behind me.
  • rmaddy
    rmaddy over 10 years
    +1 for beating me by 10 seconds with a nearly identical answer. :)
  • Rainier Wolfcastle
    Rainier Wolfcastle over 10 years
    Thank you for this. I wanted to avoid double handling but if this is accepted practise then I can live with it if I know I'm not committing some sloppy coding violation. Thank you everyone, too. I don't have enough experience points to vote up anybody but I am truly grateful for all the solutions provided.
  • Alexander
    Alexander almost 10 years
    You can just do "![isDirectory boolValue]", booleans don't need comparisons to literals for if statements.