What is the difference between a file URL and a web URL, and URL(fileURLWithPath:) and URL(string:)?

2.3.2 · L1 · Interview

Predict first

What does this print?

print(URL(string: "/tmp/x")!.isFileURL, URL(fileURLWithPath: "/tmp/x").isFileURL)
  • true true
  • false true
  • false false

Predict first

What does this print?

let u = URL(fileURLWithPath: "/a/b")
print(u.path, u.absoluteString)
  • /a/b /a/b
  • /a/b file:///a/b

Mental model. A file path is a street address inside your own building. A web URL includes the city and the country.

URL(fileURLWithPath:) takes a file system path, adds the file:// scheme, resolves a relative path against the current directory, and escapes characters as needed. URL(string:) parses URL text as is: "/tmp/x" has no scheme, so it is not a file URL, and opening it will go wrong.

Read a file’s path with url.path (or path(percentEncoded: false)), not absoluteString, which is the escaped file:///… form. User-picked files outside your sandbox need a security-scoped URL: call startAccessingSecurityScopedResource() and balance it with stop…. On Apple platforms a path can also appear as /private/var/… or /var/…, so compare with resolvingSymlinksInPath().

Only the second form knows the text is a file path, so only it adds the file:// scheme.

path is the plain path; absoluteString is the full escaped URL.

Common traps

  • Using URL(string:) for a path. You get a URL with no scheme, and file APIs reject it.
  • Showing absoluteString to a user. They see %20 for every space. Show the last path component or the decoded path.

They might follow up with

  • What is a security-scoped bookmark? Saved access to a user-chosen file that survives relaunch, created from a picker URL.
  • How do you tell files from folders? Ask for .isDirectoryKey in the resource values, or pass isDirectory: when you know.

Related questions

  • 2.3.1 What is a URL in Foundation, and what does URL(string:) accept?
  • 2.3.6 Where should an iOS app put files: Documents, Application Support, Caches or tmp?

← What is a URL in Foundation, and what does URL(string:) accept?   How do you build, change and resolve URL paths safely? →