Get directory contents in date modified order

23,615

Solution 1

nall's code above pointed me in the right direction, but I think there are some mistakes in the code as posted above. For instance:

  1. Why is filesAndProperties allocated using NMutableDictonary rather than an NSMutableArray?

  2. 
    NSDictionary* properties = [[NSFileManager defaultManager]
                                            attributesOfItemAtPath:NSFileModificationDate
                                            error:&error];
    
    
    The code above is passing the wrong parameter for attributesOfItemAtPath - it should be attributesOfItemAtPath:path

  3. Your are sorting the files array, but you should be sorting filesAndProperties.


I have implemented the same, with corrections, and using blocks and posted below:


    NSArray *searchPaths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
    NSString* documentsPath = [searchPaths objectAtIndex: 0]; 

    NSError* error = nil;
    NSArray* filesArray = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsPath error:&error];
    if(error != nil) {
        NSLog(@"Error in reading files: %@", [error localizedDescription]);
        return;
    }

    // sort by creation date
    NSMutableArray* filesAndProperties = [NSMutableArray arrayWithCapacity:[filesArray count]];
    for(NSString* file in filesArray) {
        NSString* filePath = [iMgr.documentsPath stringByAppendingPathComponent:file];
        NSDictionary* properties = [[NSFileManager defaultManager]
                                    attributesOfItemAtPath:filePath
                                    error:&error];
        NSDate* modDate = [properties objectForKey:NSFileModificationDate];

        if(error == nil)
        {
            [filesAndProperties addObject:[NSDictionary dictionaryWithObjectsAndKeys:
                                           file, @"path",
                                           modDate, @"lastModDate",
                                           nil]];                 
        }
    }

        // sort using a block
        // order inverted as we want latest date first
    NSArray* sortedFiles = [filesAndProperties sortedArrayUsingComparator:
                            ^(id path1, id path2)
                            {                               
                                // compare 
                                NSComparisonResult comp = [[path1 objectForKey:@"lastModDate"] compare:
                                                           [path2 objectForKey:@"lastModDate"]];
                                // invert ordering
                                if (comp == NSOrderedDescending) {
                                    comp = NSOrderedAscending;
                                }
                                else if(comp == NSOrderedAscending){
                                    comp = NSOrderedDescending;
                                }
                                return comp;                                
                            }];

Solution 2

How about this:

// Application documents directory
NSURL *documentsURL = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];

NSArray *directoryContent = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:documentsURL
                                                          includingPropertiesForKeys:@[NSURLContentModificationDateKey]
                                                                             options:NSDirectoryEnumerationSkipsHiddenFiles
                                                                               error:nil];

NSArray *sortedContent = [directoryContent sortedArrayUsingComparator:
                        ^(NSURL *file1, NSURL *file2)
                        {
                            // compare
                            NSDate *file1Date;
                            [file1 getResourceValue:&file1Date forKey:NSURLContentModificationDateKey error:nil];

                            NSDate *file2Date;
                            [file2 getResourceValue:&file2Date forKey:NSURLContentModificationDateKey error:nil];

                            // Ascending:
                            return [file1Date compare: file2Date];
                            // Descending:
                            //return [file2Date compare: file1Date];
                        }];

Solution 3

Simpler...

NSArray*  filelist_sorted;
filelist_sorted = [filelist_raw sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
    NSDictionary* first_properties  = [[NSFileManager defaultManager] attributesOfItemAtPath:[NSString stringWithFormat:@"%@/%@", path_thumb, obj1] error:nil];
    NSDate*       first             = [first_properties  objectForKey:NSFileModificationDate];
    NSDictionary* second_properties = [[NSFileManager defaultManager] attributesOfItemAtPath:[NSString stringWithFormat:@"%@/%@", path_thumb, obj2] error:nil];
    NSDate*       second            = [second_properties objectForKey:NSFileModificationDate];
    return [second compare:first];
}];

Solution 4

It's too slow

[[NSFileManager defaultManager]
                                attributesOfItemAtPath:NSFileModificationDate
                                error:&error];

Try this code:

+ (NSDate*) getModificationDateForFileAtPath:(NSString*)path {
    struct tm* date; // create a time structure
    struct stat attrib; // create a file attribute structure

    stat([path UTF8String], &attrib);   // get the attributes of afile.txt

    date = gmtime(&(attrib.st_mtime));  // Get the last modified time and put it into the time structure

    NSDateComponents *comps = [[NSDateComponents alloc] init];
    [comps setSecond:   date->tm_sec];
    [comps setMinute:   date->tm_min];
    [comps setHour:     date->tm_hour];
    [comps setDay:      date->tm_mday];
    [comps setMonth:    date->tm_mon + 1];
    [comps setYear:     date->tm_year + 1900];

    NSCalendar *cal = [NSCalendar currentCalendar];
    NSDate *modificationDate = [[cal dateFromComponents:comps] addTimeInterval:[[NSTimeZone systemTimeZone] secondsFromGMT]];

    [comps release];

    return modificationDate;
}
Share:
23,615
nevan king
Author by

nevan king

Mostly questions and answers about iOS & maps

Updated on November 02, 2020

Comments

  • nevan king
    nevan king over 3 years

    Is there an method to get the contents of a folder in a particular order? I'd like an array of file attribute dictionaries (or just file names) ordered by date modified.

    Right now, I'm doing it this way:

    • get an array with the file names
    • get the attributes of each file
    • store the file's path and modified date in a dictionary with the date as a key

    Next I have to output the dictionary in date order, but I wondered if there's an easier way? If not, is there a code snippet somewhere which will do this for me?

    Thanks.

  • nevan king
    nevan king over 14 years
    Thanks for the answer. There seems to be a few things that won't work with the iPhone SDK here (NSURLContentModificationDateKey and some other NSURL methods).
  • nevan king
    nevan king over 14 years
    I've started trying to change it to work with the iPhone SDK, but getResourceValue doesn't exist there. I'll look for an array sort for iPhone.
  • nall
    nall over 14 years
    nevan, I updated this to work within the constraints of the iPhone SDK
  • Roger
    Roger over 13 years
    Lots of little bugs in this code fragment ... I don't think this code is tested on iOS.
  • Jonathan.
    Jonathan. over 12 years
    To invert the ordering you can just multiply the comparison result by -1.
  • Admin
    Admin over 12 years
    To invert the ordering you can just use return [[path2 objectForKey:@"lastModDate"] compare:[path1 objectForKey:@"lastModDate"]];
  • Ivan Kovacevic
    Ivan Kovacevic over 11 years
    I was just looking for the solution for this myself and ended up using the above code. So I've put it here cause I think its cleaner than what others have provided ;)
  • ski_squaw
    ski_squaw over 10 years
    This is much faster. 4x faster in my tests. I ran into one bug with this though. My gmtime is returning UTC not GMT. Some times had a one hour difference which caused problems.
  • ski_squaw
    ski_squaw over 10 years
    Adjust code as follows: NSCalendar *cal = [NSCalendar currentCalendar]; NSTimeZone *tz = [NSTimeZone timeZoneWithAbbreviation:[[NSString alloc] initWithUTF8String:date->tm_zone]]; cal.timeZone = tz;
  • Maciej Swic
    Maciej Swic over 9 years
    You need to #import "sys/stat.h"
  • DJTano
    DJTano over 6 years
    what is path_thumb ?