Testing file existence using NSURL

CocoaOsx Snow-LeopardNsurlCore FoundationNsfilemanager

Cocoa Problem Overview


Snow Leopard introduced many new methods to use NSURL objects to refer to files, not pathnames or Core Services' FSRefs.

However, there's one task I can't find a URL-based method for: Testing whether a file exists. I'm looking for a URL-based version of -[NSFileManager fileExistsAtPath:]. Like that method, it should return YES if the URL describes anything, whether it's a regular file, a directory, or anything else.

I could attempt to look up various resource values, but none of them are explicitly guaranteed to not exist if the file doesn't, and some of them (e.g., NSURLEffectiveIconKey) could be costly if it does.

I could just use NSFileManager's fileExistsAtPath:, but if there's a more modern method, I'd prefer to use that.

Is there a simple method or function in Cocoa, CF, or Core Services that's guaranteed/documented to tell me whether a given file (or file-reference) URL refers to a file-system object that exists?

Cocoa Solutions


Solution 1 - Cocoa

NSURL does have this method:

- (BOOL)checkResourceIsReachableAndReturnError:(NSError **)error

Which "Returns whether the resource pointed to by a file URL can be reached."

NSURL *theURL = [NSURL fileURLWithPath:@"/Users/elisevanlooij/nonexistingfile.php" 
		       isDirectory:NO];
NSError *err;
if ([theURL checkResourceIsReachableAndReturnError:&err] == NO)
    [[NSAlert alertWithError:err] runModal];

Solution 2 - Cocoa

On iOS I couldn't find any other way...

NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"file.type"];
if ([[NSFileManager defaultManager] fileExistsAtPath:[storeURL path]]) {...}

Solution 3 - Cocoa

Here is the Swift 2 answer:

var error:NSError?
let folderExists = theURL.checkResourceIsReachableAndReturnError(&error)

Solution 4 - Cocoa

Determining if a given file (or file-reference) URL refers to a file-system object that exists is inherently costly for remote resources, the 10.6 only (no iPhoneOS) api's for this CFURLResourceIsReachable() and [NSURL checkResourceIsReachableAndReturnError:] are both synchronous, even if you would be using them, for a lot of files you would still be looking at a significant delay overhead.

What you should do is implement your own asynchronous checking routine with caching that separately creates a list of valid resources.

Otherwise the notes for CFURLResourceIsReachable in the header state : > An example would be periodic maintenance of UI state that depends > on the existence of a particular document. When performing an > operation such as opening a file, it is more efficient to simply try the > operation and handle failures than to check first for reachability.

Solution 5 - Cocoa

Because NSURL can represents more that local file-systems, I don't think that there is a generic method that can test for their existence in a reliable way. At least, the Cocoa foundation does not contains such a function (as far as I know).

If you only deal with local file-systems, I suggest you to create a category for NSURL or for NSFileManager, with a urlExists: message. It would convert the NSURL to a NSString (normalized path) and then invoke the [NSFileManager fileExistsAtPath:] message.

Solution 6 - Cocoa

In Swift you can use the checkResourceIsReachable() method, which unfortunately will either return true (if the file is reachable) or throw an error (explaining why it cannot be reached).

To get a bool true/false value instead, use this syntax:

let exists = (try? inputFile.checkResourceIsReachable()) ?? false

If you'd like to log the error:

let exists: Bool
do {
  exists = try inputFile.checkResourceIsReachable()
} catch {
  exists = false
  print(error.localizedDescription)
}

Keep in mind this is an expensive operation and it could be out of date immediately after (if some other process is deleting a or unmounts a disk file while you're checking if it exists).

In general the preferred approach is not to check wether a file exists, instead simply attempt to read or write to a file and handle any error afterwards if it fails.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPeter HoseyView Question on Stackoverflow
Solution 1 - CocoaElise van LooijView Answer on Stackoverflow
Solution 2 - CocoaAntónio AzevedoView Answer on Stackoverflow
Solution 3 - CocoaWilliam EntrikenView Answer on Stackoverflow
Solution 4 - CocoavalexaView Answer on Stackoverflow
Solution 5 - CocoaLaurent EtiembleView Answer on Stackoverflow
Solution 6 - CocoaAbhi BeckertView Answer on Stackoverflow