Is there a safer way to create a directory if it does not exist?

31,039

Solution 1

You can actually skip the if, even though Apple's docs say that the directory must not exist, that is only true if you are passing withIntermediateDirectories:NO

That puts it down to one call. The next step is to capture any errors:

NSError * error = nil;
[[NSFileManager defaultManager] createDirectoryAtPath:bundlePath
                          withIntermediateDirectories:YES
                                           attributes:nil
                                                error:&error];
if (error != nil) {
    NSLog(@"error creating directory: %@", error);
    //..
}

This will not result in an error if the directory already exists.

Solution 2

For Swift 3.0

do {
    try FileManager.default.createDirectory(atPath: folder, withIntermediateDirectories: true, attributes: nil)
} catch {
    print(error)
}

Solution 3

Swift 4.2

let fileManager = FileManager.default
let documentsURL =  fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!

let imagesPath = documentsURL.appendingPathComponent("Images")
do
{
    try FileManager.default.createDirectory(atPath: imagesPath.path, withIntermediateDirectories: true, attributes: nil)
}
catch let error as NSError
{
    NSLog("Unable to create directory \(error.debugDescription)")
}

Solution 4

Swift 5.0

let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentsDirectory = paths[0]
let docURL = URL(string: documentsDirectory)!
let dataPath = docURL.appendingPathComponent("MyFolder")
if !FileManager.default.fileExists(atPath: dataPath.absoluteString) {
    do {
        try FileManager.default.createDirectory(atPath: dataPath.absoluteString, withIntermediateDirectories: true, attributes: nil)
    } catch {
        print(error.localizedDescription);
    }
}

Solution 5

NSFileManager *fileManager= [NSFileManager defaultManager]; 
if(![fileManager fileExistsAtPath:directory isDirectory:&isDir])
    if(![fileManager createDirectoryAtPath:directory withIntermediateDirectories:YES attributes:nil error:NULL])
        NSLog(@"Error: Create folder failed %@", directory);

From an SO topic here.

After creating a directory, you can flush the file system then check to see if your newly created directory exists. This is probably overkill, but you can never have too much overkill.

Share:
31,039
dontWatchMyProfile
Author by

dontWatchMyProfile

Based in the Czech Republic. Like to swim, like to eat ice cream. The big Cocoa and Cocoa Touch online Training / Session Videos list

Updated on June 18, 2020

Comments

  • dontWatchMyProfile
    dontWatchMyProfile almost 4 years

    I've found this way of creating a directory if it does not exist. But it looks a bit wonky and I am afraid that this can go wrong in 1 of 1000 attempts.

    if(![[NSFileManager defaultManager] fileExistsAtPath:bundlePath]) {
        [[NSFileManager defaultManager] createDirectoryAtPath:bundlePath withIntermediateDirectories:YES attributes:nil error:NULL];
    }
    

    There is only this awkward method fileExistsAtPath which also looks for files and not only directories. But for me, the dangerous thing is: What if this goes wrong? What shall I do? What is best practice to guarantee that the directory is created, and only created when it does not exist?

    I know file system operations are never safe. Device could loose battery power suddenly just in the moment where it began shoveling the bits from A to B. Or it can stumble upon a bad bit and hang for a second. Maybe in some seldom cases it returns YES even if there is no directory. Simply put: I don't trust file system operations.

    How can I make this absolutely safe?

  • dontWatchMyProfile
    dontWatchMyProfile almost 13 years
    Great! What should I do if there occurs an error? Does it make sense to attempt and try again? (at least a few times...? and what if that does not help?)
  • dontWatchMyProfile
    dontWatchMyProfile almost 13 years
    What do you mean by "flush the file system"?
  • Mathias
    Mathias almost 13 years
    I'm not sure what to do if there is an error. It depends how fancy you want to get. You could look for specific errors and handle them differently, or try to create a different path. Perhaps let the user choose a different one?
  • Charles Burns
    Charles Burns almost 13 years
    dontWatchMyProfile: Writes to a disk (or in this case, FLASH storage) are often first written to much faster RAM, then committed to main storage as performance and load allow. Flushing that cache, or "syncing", commands the system to "write the entire contents of the cache right now." This is important in case, as the OP says, power is lost. I have little information regarding file IO on the iPhone and related devices, but a hopefully relevant SO thread exists here: stackoverflow.com/questions/459537/…
  • James Moore
    James Moore over 11 years
    Between line two and line three you should add a comment like this: // Right here, we switch processes and someone else can create a file with the name we just passed to fileExistsAtPath:isDirectory: - so this check isn't really worth doing.
  • Mathias
    Mathias about 11 years
    @Sven: I don't see how it makes a difference to the logic?
  • jscs
    jscs over 6 years
    Cocoa error handling generally does not promise that the error pointer will be NULL on success, only that it will be populated on failure.