1

What is the practical difference between (FileManager)fileExistsAtPath:isDirectory: and (URL).hasDirectoryPath?

I'm following some tutorials and they first used the FileManager approach, but then appear to consistently use the URL method afterwards. In my eyes, the URL approach seems more concise and easier to remember. Is there ever any reason to use the FileManager method instead? (and please provide examples if the answer is yes)

mredig
  • 1,736
  • 1
  • 16
  • 29

1 Answers1

7

Contrary to the accepted answer, the difference is not only availability. The FileManager API actually accesses the file pointed to by the URL on the disk to see if it is a directory, whereas hasDirectoryPath does not; it only checks whether the URL's path has a slash (/) at the end of it, which indicates that the path points to a directory. You can verify this by making an app and running it in the File Activity instrument; with FileManager you will see an lstat64 on the directory, whereas with hasDirectoryPath you will not.

This has a few effects:

  1. hasDirectoryPath will obviously perform much faster, since it does not access the disk.

  2. However, hasDirectoryPath may give incorrect results if the URL's path is incorrect regarding the presence of the trailing slash. For example:

    URL(string: "file:///usr/bin")!.hasDirectoryPath // evaluates to false URL(string: "file:///usr/bin/")!.hasDirectoryPath // evaluates to true

  3. Finally, hasDirectoryPath can work on a non-file: URL, such as an http: URL, whereas FileManager obviously cannot.

With all that said, when you need to check via the file system, it is better to use the URL-based mechanism for this rather than path-based ones in FileManager:

let isDir = (try? self.resourceValues(forKeys: [.isDirectoryKey]))?.isDirectory ?? false
Charles Srstka
  • 16,665
  • 3
  • 34
  • 60
  • Your answer is only correct when you use the `URL(string: "file://\(path)")` constructor. `URL(fileURLWithPath: path)` will check if the file the path is pointing to is a directory. `URL(fileURLWithPath: "/usr/bin").hasDirectoryPath` returns `true` on my machine. – YourMJK Aug 17 '22 at 15:10