Question

I am downloading images to my app which after a few weeks the user will not care about. I download them to the app so they will not have to be downloaded every launch. The problem is I do not want the Documents folder to get bigger than it has to over time. So I thought I could "clean up" file older than a Month.

The problem is, there will be a few files in there that WILL be older than a month but that I do NOT want to delete. They will be Static Named files so they will be easy to identify and there will only be 3 or 4 of them. While there might be a few dozen old files I want to delete. So heres an example:

picture.jpg           <--Older than a month DELETE
picture2.jpg          <--NOT older than a month Do Not Delete
picture3.jpg          <--Older than a month DELETE
picture4.jpg          <--Older than a month DELETE
keepAtAllTimes.jpg    <--Do not delete no matter how old
keepAtAllTimes2.jpg   <--Do not delete no matter how old
keepAtAllTimes3.jpg   <--Do not delete no matter how old

How could I selectively delete these files?

Thanks in advance!

Was it helpful?

Solution

Code to delete files which are older than two days. Originally I answered here. I tested it and it was working in my project.

P.S. Be cautious before you delete all files in Document directory because doing so you might end up losing your Database file(If you are using..!!) there which may cause trouble for your Application. Thats why I have kept if condition there. :-))

// Code to delete images older than two days.
   #define kDOCSFOLDER [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]

NSFileManager* fileManager = [[[NSFileManager alloc] init] autorelease];
NSDirectoryEnumerator* en = [fileManager enumeratorAtPath:kDOCSFOLDER];    

NSString* file;
while (file = [en nextObject])
{
    NSLog(@"File To Delete : %@",file);
    NSError *error= nil;

    NSString *filepath=[NSString stringWithFormat:[kDOCSFOLDER stringByAppendingString:@"/%@"],file];


    NSDate   *creationDate =[[fileManager attributesOfItemAtPath:filepath error:nil] fileCreationDate];
    NSDate *d =[[NSDate date] dateByAddingTimeInterval:-1*24*60*60];

    NSDateFormatter *df=[[NSDateFormatter alloc]init];// = [NSDateFormatter initWithDateFormat:@"yyyy-MM-dd"];
    [df setDateFormat:@"EEEE d"]; 

    NSString *createdDate = [df stringFromDate:creationDate];

     NSString *twoDaysOld = [df stringFromDate:d];

    NSLog(@"create Date----->%@, two days before date ----> %@", createdDate, twoDaysOld);

    // if ([[dictAtt valueForKey:NSFileCreationDate] compare:d] == NSOrderedAscending)
    if ([creationDate compare:d] == NSOrderedAscending)

    {
        if([file isEqualToString:@"RDRProject.sqlite"])
        {

            NSLog(@"Imp Do not delete");
        }

        else
        {
             [[NSFileManager defaultManager] removeItemAtPath:[kDOCSFOLDER stringByAppendingPathComponent:file] error:&error];
        }
    }
}

OTHER TIPS

You can get the file creation date, look at this SO Post and then just compare the dates. and create two different arrays for files needs to be deleted and non to be deleted..

My two cents worth. Change meetsRequirement to suit.

func cleanUp() {
    let maximumDays = 10.0
    let minimumDate = Date().addingTimeInterval(-maximumDays*24*60*60)
    func meetsRequirement(date: Date) -> Bool { return date < minimumDate }

    func meetsRequirement(name: String) -> Bool { return name.hasPrefix(applicationName) && name.hasSuffix("log") }

    do {
        let manager = FileManager.default
        let documentDirUrl = try manager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
        if manager.changeCurrentDirectoryPath(documentDirUrl.path) {
            for file in try manager.contentsOfDirectory(atPath: ".") {
                let creationDate = try manager.attributesOfItem(atPath: file)[FileAttributeKey.creationDate] as! Date
                if meetsRequirement(name: file) && meetsRequirement(date: creationDate) {
                    try manager.removeItem(atPath: file)
                }
            }
        }
    }
    catch {
        print("Cannot cleanup the old files: \(error)")
    }
}

To find creation date of your file, you can refer to a very useful StackOverflow post:

iOS: How do you find the creation date of a file?

Refer to this post, this may help you in deleting them. You can just get a rough idea on what needs to be done for deletion of those data from Documents Directory:

How to delete files from iPhone's document directory which are older more than two days

Hope this helps you.

Here's a function that doesn't use string comparison for the dates and prefetches the modification time in the enumerator:

+ (NSArray<NSURL *> *)deleteFilesOlderThan:(NSDate *)earliestDateAllowed
                               inDirectory:(NSURL *)directory {
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSDirectoryEnumerator<NSURL *> *enumerator =
        [fileManager enumeratorAtURL:directory
            includingPropertiesForKeys:@[ NSURLContentModificationDateKey ]
                               options:0
                          errorHandler:^BOOL(NSURL *_Nonnull url, NSError *_Nonnull error) {
                              NSLog(@"Failed while enumerating directory '%@' for files to "
                                         @"delete: %@ (failed on file '%@')",
                                         directory.path, error.localizedDescription, url.path);
                              return YES;
                          }];

    NSURL *file;
    NSError *error;
    NSMutableArray<NSURL *> *filesDeleted = [NSMutableArray new];
    while (file = [enumerator nextObject]) {
        NSDate *mtime;
        if (![file getResourceValue:&mtime forKey:NSURLContentModificationDateKey error:&error]) {
            NSLog(@"Couldn't fetch mtime for file '%@': %@", file.path, error);
            continue;
        }

        if ([earliestDateAllowed earlierDate:mtime] == earliestDateAllowed) {
            continue;
        }

        if (![fileManager removeItemAtURL:file error:&error]) {
            NSLog(@"Couldn't delete file '%@': %@", file.path, error.localizedDescription);
            continue;
        }
        [filesDeleted addObject:file];
    }
    return filesDeleted;
}

If you don't care about the files that got deleted you could make it return BOOL to indicate whether there were any errors, or simply void if you just want to make a best-effort attempt.

To selectively keep some of the files, either add a regular expression argument to the function that should match files to keep, and add a check for that in the while loop (seems to fit your use case best), or if there's a discrete amount of files with different patterns you could accept a NSSet with the filenames to keep and check for inclusion in the set before proceeding to the delete.

Also just mentioning this here since it might be relevant for some: The file system on iOS and OSX doesn't store mtime with greater precision than a second, so watch out for that if you require millisecond-precision or similar.

Corresponding test case to drop into your test suite if you want:

@interface MCLDirectoryUtilsTest : XCTestCase

@property NSURL *directory;

@end


@implementation MCLDirectoryUtilsTest

- (void)setUp {
    NSURL *tempdir = [NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES];
    self.directory = [tempdir URLByAppendingPathComponent:[NSUUID UUID].UUIDString isDirectory:YES];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    [fileManager createDirectoryAtURL:self.directory
          withIntermediateDirectories:YES
                           attributes:nil
                                error:nil];
}


- (void)tearDown {
    NSFileManager *fileManager = [NSFileManager defaultManager];
    [fileManager removeItemAtURL:self.directory error:nil];
}


- (void)testDeleteFilesOlderThan {
    NSFileManager *fileManager = [NSFileManager defaultManager];
    // Create one old and one new file
    [fileManager createFileAtPath:[self.directory URLByAppendingPathComponent:@"oldfile"].path
                         contents:[NSData new]
                       attributes:@{
                           NSFileModificationDate : [[NSDate new] dateByAddingTimeInterval:-120],
                       }];
    [fileManager createFileAtPath:[self.directory URLByAppendingPathComponent:@"newfile"].path
                         contents:[NSData new]
                       attributes:nil];

    NSArray<NSURL *> *filesDeleted =
        [MCLUtils deleteFilesOlderThan:[[NSDate new] dateByAddingTimeInterval:-60]
                           inDirectory:self.directory];
    XCTAssertEqual(filesDeleted.count, 1);
    XCTAssertEqualObjects(filesDeleted[0].lastPathComponent, @"oldfile");
    NSArray<NSString *> *contentsInDirectory =
        [fileManager contentsOfDirectoryAtPath:self.directory.path error:nil];
    XCTAssertEqual(contentsInDirectory.count, 1);
    XCTAssertEqualObjects(contentsInDirectory[0], @"newfile");
}

In Swift 3 and 4, to delete a specific file in DocumentsDirectory

do{
    try FileManager.default.removeItem(atPath: theFile)
} catch let theError as Error{
    print("file not found \(theError)")
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top