2

Is there a faster file system API that I can use if I only need to know if a file is a folder/symlink and its size. I'm currently using [NSFileManager attributesOfItemAtPath...] and only NSFileSize and NSFileType.

Are there any bulk filesystem enumeration APIs I should be using? I suspect this could be faster without having to jump in and out of user code.

My goal is to quickly recurse through directories to get a folders true file size and currently calling attributesOfItemAtPath is my 95% bottleneck.

Some of the code I'm currently using:

NSDictionary* properties = [fileManager attributesOfItemAtPath:filePath error:&error];
long long fileSize = [[properties objectForKey:NSFileSize] longLongValue];
NSObject* fileType = [[properties objectForKey:NSFileType isEqual:NSFileTypeDirectory];
JonLeah
  • 181
  • 3
  • 14
  • Just a wild guess, something like http://stackoverflow.com/questions/5749488/iterating-through-files-in-a-folder-with-nested-folders-cocoa ? – ta.speot.is Feb 27 '13 at 03:39

3 Answers3

3

If you want to get really hairy, the Mac OS kernel implements a unique getdirentriesattr() system call which will return a list of files and attributes from a specified directory. It's messy to set up and call, and it's not supported on all filesystems (!), but if you can get it to work for you, it can speed things up significantly.

There's also a closely related searchfs() system call which can be used to rapidly search for files. It's subject to most of the same gotchas.

  • Hi, I've just found out about searchfs, and I was looking for an example that retrieve the file fullpath in it's output buffer. So far I keep getting errno EINVAL which means that my parameters combination to `searchfs` is somehow not supported. perhaps, if you have any experience using this command, you can point me to a relevant example (I couldn't find in the web). Thanks ! – Zohar81 Apr 17 '18 at 08:56
  • @Zohar81 How about github.com/sveinbjornt/searchfs ? – svth May 11 '19 at 17:15
1

Whether it's faster or not I'm not certain, but NSURL will give you this information via getResourceValue:forKey:error:

NSError * e;
NSNumber * isDirectory;
BOOL success = [URLToFile getResourceValue:&isDirectory
                                    forKey:NSURLIsDirectoryKey 
                                     error:&e];
if( !success ){
   // error
}

NSNumber * fileSize;
BOOL success = [URLToFile getResourceValue:&fileSize
                                    forKey:NSURLFileSizeKey
                                     error:&e];

You might also find it convenient to wrap this up if you don't really care about the error:

@implementation NSURL (WSSSimpleResourceValueRetrieval)

- (id)WSSResourceValueForKey: (NSString *)key
{
    id value = nil;
    BOOL success = [self getResourceValue:&value
                                   forKey:key 
                                    error:nil];
    if( !success ){
        value = nil;
    }
    
    return value;
}

@end

This is given as the substitute for the deprecated File Manager function FSGetCatalogInfo(), which is used in a solution in an old Cocoa-dev thread that Dave DeLong gives the thumbs up to.

For the enumeration part, the File System Programming Guide has a section "Getting the Contents of a Directory in a Single Batch Operation", which discusses using contentsOfDirectoryAtURL:includingPropertiesForKeys:options:error:

Community
  • 1
  • 1
jscs
  • 63,694
  • 13
  • 151
  • 195
  • +1 the last point is important -- if using Cocoa APIs, use an API such as `contentsOfDirectoryAtURL:includingPropertiesForKeys:options:error:` (or the enumerator equivalent) and fetch only what you need. – justin Feb 27 '13 at 06:45
1

You can use stat and lstat. Take a look at this answer for calculating directory size.
CPU raises with attributesOfItemAtPath:error:

Community
  • 1
  • 1
Parag Bafna
  • 22,812
  • 8
  • 71
  • 144