iOS: How to delete all existing files with specific extension from the documents dir?
Asked Answered
E

2

7

When I update my iOS app, I want to delete any existing sqlite databases in the Documents directory. Right now, on an application update, I copy the database from the bundle to the documents directory and name it by appending the bundle version. So, on the update, I also want to delete any old versions that might exist.

I just want to be able to delete all sqlite files, without having to loop through and look for ones from previous versions. Is there any way to wildcard the removeFileAtPath: method?

Ewens answered 12/2, 2013 at 16:32 Comment(3)
Short answer: No. Why don't you want to loop? It's fun.Oblast
You need to use NSFileManager to get an array of the matches. [Sample code here][1]. [1]: https://mcmap.net/q/1476717/-how-to-find-multiple-files-with-wildcard-expression-in-objective-cSailing
What does the NSFileManager spec say?Shea
B
17

So, you'd like to delete all *.sqlite files? There is no way to avoid looping, but you can limit it by using a NSPredicate to filter out non-sql files first and ensure speedy performance using fast enumeration. Here's a method to do it:

- (void)removeAllSQLiteFiles    
{
    NSFileManager  *manager = [NSFileManager defaultManager];

    // the preferred way to get the apps documents directory
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];

    // grab all the files in the documents dir
    NSArray *allFiles = [manager contentsOfDirectoryAtPath:documentsDirectory error:nil];

    // filter the array for only sqlite files
    NSPredicate *fltr = [NSPredicate predicateWithFormat:@"self ENDSWITH '.sqlite'"];
    NSArray *sqliteFiles = [allFiles filteredArrayUsingPredicate:fltr];

    // use fast enumeration to iterate the array and delete the files
    for (NSString *sqliteFile in sqliteFiles)
    {
       NSError *error = nil;
       [manager removeItemAtPath:[documentsDirectory stringByAppendingPathComponent:sqliteFile] error:&error];
       NSAssert(!error, @"Assertion: SQLite file deletion shall never throw an error.");
    }
}
Brunhild answered 12/2, 2013 at 16:55 Comment(4)
Thanks - The code seems to work but the file never actually gets deleted when I examine the app in Organizer. Is this just a 'feature' of running in development mode?Ewens
@Ewens It was a bug in the code. I didn't give the full path to removeItemAtPath so the files were not found and deleted. Fixed now.Brunhild
I would suggest using NSError* error = nil; error:&error instead of error:nil for removeItemAtPath: then you can log the error if it exists to help you debug any issues.Magdalen
@Magdalen Hah! I was right in the middle of doing that when you posted. I prefer to use asserts to ensure the validity of most of my production code rather than an NSLog though.Brunhild
P
1

Swift version of correct answer:

func removeAllSQLiteFiles() {
    let fileManager = FileManager.default

    let documentsDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
    let urlDocumentsDirectory = URL(fileURLWithPath: documentsDirectory)
    guard let allFiles = try? fileManager.contentsOfDirectory(at: urlDocumentsDirectory, includingPropertiesForKeys: nil) else {
        return
    }
    let sqliteFiles = allFiles.filter { $0.pathExtension.elementsEqual("sqlite") }
    for sqliteFile in sqliteFiles {
        do {
            try fileManager.removeItem(at: sqliteFile)
        } catch {
            assertionFailure(error.localizedDescription)
        }
    }
}
Pastelist answered 1/9, 2021 at 23:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.