Testing file existence using NSURL

44,254

Solution 1

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

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

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

Solution 3

Here is the Swift 2 answer:

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

Solution 4

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

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.

Share:
44,254
Nico
Author by

Nico

Author of numerous little Mac apps (and a blog). From April 21, 2014 until August 2018, I worked for Apple, as a Software QA Engineer on the Foundation framework team. Answers and edits before April 21, 2014 were written before I knew anything internal. Anything I posted during that time was only about APIs and behaviors that were public—i.e., verifiable in released software or promised by documentation. Above all, nothing I've written here, or anywhere else public, should be construed as having ever been an opinion or statement from Apple, nor a promise of future behavior or features. Opinions, when I give them, are my own.

Updated on June 25, 2020

Comments

  • Nico
    Nico almost 4 years

    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?

  • Justin Searls
    Justin Searls about 14 years
    To any iPhone OS devs thrown off by this answer: checkResourceIsReachableAndReturnError: is only available in 10.6 and later and not yet available in the iPhone SDK.
  • Nico
    Nico over 13 years
    Update: It is available as of iOS 4.
  • A . Radej
    A . Radej over 13 years
    The iOS docs in XCode 3.2.5 (which supports iOS 4.2) state: "This method is unimplemented in iOS, so it performs no operation."
  • Ron
    Ron over 12 years
    Another update ... it performed no operation in iOS4, although apparently it is now supported on the iPhone as of iOS5.0
  • Kenny Winker
    Kenny Winker over 12 years
    You can couple the aforementioned checkResourceIsReachableAndReturnError: with isFileURL to keep it sane.
  • Abhi Beckert
    Abhi Beckert about 10 years
    I doubt it's slow... NSURL maintains a link to the HFS+ filesystem entry that it represents. According to Apple, URLs are much faster than paths for all filesystem operations.
  • Cbas
    Cbas about 8 years
    Note that this only works for local files and will always return NO for remote URLs
  • devios1
    devios1 about 8 years
    Good lord who named this function?
  • DawnSong
    DawnSong almost 8 years
    It should be checkResourceIsReachable()->Void and throw exception, however, what you said is correct for Xcode 7.x
  • Nico
    Nico almost 8 years
    *throw error. Swift errors are different from Objective-C exceptions. Similar syntax, but different purpose.