What's the least resource intensive way to find out if an object is a folder?

I need to sort 8145 objects (there may be more) for files and folders. (Tested on A8X).

First method.

for(NSString *filename in FilesList) //This method takes an average of 7.7 seconds.
{
    fileExtension = (__bridge CFStringRef)[filename pathExtension];
    fileUTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, fileExtension, NULL);
    if ([Β­[Β­[Β­[NSFileManager defaultManager] attributesOfItemAtPath:[FolderPath stringByAppendingPathComponent:filename] error:nil] fileType] isEqualToString:@"NSFileTypeDirectory"] && !UTTypeConformsTo(fileUTI, kUTTypeRTFD))
       [OnlyFolderList addObject:filename];
    else
       [OnlyFilesList addObject:filename];
}

      

Second method.

for(NSString *filename in FilesList) //This method takes an average of 2.9 seconds.
{
     fileExtension = (__bridge CFStringRef)[filename pathExtension];
     fileUTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, fileExtension, NULL);
      [[NSFileManager defaultManager] fileExistsAtPath:[FolderPath stringByAppendingPathComponent:filename] isDirectory:&isDir];
      if (isDir && !UTTypeConformsTo(fileUTI, kUTTypeRTFD))
          [OnlyFolderList addObject:filename];
      else
          [OnlyFilesList addObject:filename];
}

      

Do you know a faster way?

----- Updated with the fastest method ----- //0.26 seconds for 8145 objects!

    NSNumber *isDirectory;
    NSError *error = nil;
    NSString *name;
    NSArray *FilesList = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:[NSURL fileURLWithPath:FolderPath] includingPropertiesForKeys:[NSArray arrayWithObjects:NSURLIsDirectoryKey,NSURLNameKey,nil] options:NSDirectoryEnumerationSkipsHiddenFiles error:nil];
    for (NSURL *url in FilesList)
    {
       [url getResourceValue:&name forKey:NSURLNameKey error:&error];
       [url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:&error];
       if ([isDirectory boolValue])
       {
           CFStringRef fileExtension = (__bridge CFStringRef)[name pathExtension];
           CFStringRef fileUTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, fileExtension, NULL);
           if (!UTTypeConformsTo(fileUTI, kUTTypeRTFD))
               [OnlyFolderList addObject:name];
           else
               [OnlyFilesList addObject:name];
       }
       else
           [OnlyFilesList addObject:name];
    }

      

+3


source to share


3 answers


Try using contentsOfDirectoryAtURL:includingPropertiesForKeys:options:error:

:



NSURL *root = ... // the root URL to get the file list from
NSFileManager *fm = [NSFileManager defaultManager];
NSError *error = nil;
NSArray *filesList = [fm contentsOfDirectoryAtURL:root includingPropertiesForKeys:@[ NSURLIsDirectoryKey, NSURLTypeIdentifierKey ] options:NSDirectoryEnumerationSkipsHiddenFiles error:&error];
if (dirURLs) {
    for (NSURL *fileURL in filesList) {
        NSString *filename = [[fileURL path] lastPathComponent];
        NSNumber *isDir = nil;
        [fileURL getResourceValue:&isDir forKey:NSURLIsDirectoryKey error:nil]
        if ([isDir boolValue]) {
            NSString *uti;
            [fileURL getResourceValue:&uti forKey:NSURLTypeIdentifierKey error:nil];
            if ([(__bridge NSString *)kUTTypeRTFD isEqualToString:uti]) {
                [OnlyFilesList addObject:filename];
            } else {
                [OnlyFoldersList addObject:filename];
            }
        } else {
            [OnlyFilesList addObject:filename];
        }
    }
} else {
    NSLog(@"Unable to get list of files in %@: %@", root, error);
}

      

+3


source


In the second method, move the Extension and fileUTI inside the test for isDir so that the code won't run if the file is not potentially a directory.

Try the following:



NSFileManager *fileManager = [NSFileManager defaultManager];
for(NSString *filename in FilesList) {
    [fileManager fileExistsAtPath:[FolderPath stringByAppendingPathComponent:filename] isDirectory:&isDir];
    if (isDir) {
        CFStringRef fileExtension = (__bridge CFStringRef)[filename pathExtension];
        CFStringRef fileUTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, fileExtension, NULL);
        if (!UTTypeConformsTo(fileUTI, kUTTypeRTFD))
            [OnlyFolderList addObject:filename];
        else
            [OnlyFilesList addObject:filename];
    }
    else
        [OnlyFilesList addObject:filename];
}

      

+1


source


Try to use BSD API directly.

static BOOL cStringHasSuffix(const char *string, const char *suffix) {
    unsigned long stringLength = strlen(string);
    unsigned long suffixLength = strlen(suffix);
    return stringLength >= suffixLength && memcmp(string + stringLength - suffixLength, suffix, suffixLength) == 0;
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    NSURL *url = [[NSBundle mainBundle] bundleURL];
    NSMutableArray *folderNames = [NSMutableArray array];
    NSMutableArray *fileNames = [NSMutableArray array];
    const char *rtfdSuffix = ".rtfd";
    DIR *dir = opendir(url.fileSystemRepresentation);
    struct dirent *item;
    while ((item = readdir(dir))) {
        NSString *name = [NSString stringWithUTF8String:item->d_name];
        if (item->d_type == 0) {
            NSLog(@"unknown type for %@", name);
        } else if (item->d_type == DT_DIR) {
            if (cStringHasSuffix(item->d_name, rtfdSuffix)) {
                [fileNames addObject:name];
            } else {
                [folderNames addObject:name];
            }
        } else if (item->d_type == DT_REG) {
            [fileNames addObject:name];
        } else {
            NSLog(@"unexpected type %d for %@", item->d_type, name);
        }
    }
    closedir(dir);

    NSLog(@"fileNames = %@", fileNames);
    NSLog(@"folderNames = %@", folderNames);
    return YES;
}

      

+1


source







All Articles