Here is a function that does not use string comparison for dates and pre-sets 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 do not need files that have been deleted, you can force it to return BOOL
to indicate if there were any errors or just void
if you just want to try with maximum effort.
To selectively save some files, add the regex argument to the function that should match the saved files, and add a check for this in the while loop (seems to be the best fit for your use), or if there is a discrete number of files with different patterns, you can accept NSSet
with file names to save and verify inclusion in the set before proceeding with deletion.
We also just mention it here, as it may be relevant for some: the iOS and OSX file system does not save mtime with more accuracy than a second, so keep an eye on this if you need a millisecond of accuracy or similar.
Relevant test case 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];
source share