Get fullpath or convert to fullpath
Asked Answered
C

2

2

When using

let directoryEnumerator = FileManager().enumerator(at: ...

in Swift 3, I get all files from the folder, e.g.

"file:///Volumes/MacOS/fasttemp/Fotos/"

The results are not including the leading path (here "/Volumes/MacOS"). So I get

"file:///fasttemp/Fotos/2005/"

How can I get the fullpath (directly from the enumerator) or convert them. I want to use URL functions, not string function manipulating by assumptions.

Calvinna answered 3/11, 2016 at 8:48 Comment(2)
"/Volumes/MacOS" is a symbolic link to "/", so both "/fasttemp/Fotos/2005/" and "/Volumes/MacOS/fasttemp/Fotos/" are absolute paths to the same file.Luminescence
Is there a function to get a specific representation for a file? I like to compare them, e.g. use them as a key. If they use different representations as string, that will fail.Calvinna
L
5

If "MacOS" is the name of your current startup disk then "/Volumes/MacOS" is a symbolic link to "/", so both "/fasttemp/Fotos/2005/" and "/Volumes/MacOS/fasttemp/Fotos/" are absolute paths to the same file.

In order to get a unique file name representation you can query a URL for its canonical path. Example:

let url = URL(fileURLWithPath: "/Volumes/MacOS/Applications/Utilities/")
if let cp = (try? url.resourceValues(forKeys: [.canonicalPathKey]))?.canonicalPath {
    print(cp)
}
// Output: "/Applications/Utilities"

This requires macOS 10.12/iOS 10 or later. On older systems you can use the realpath() system call:

if let rp = url.withUnsafeFileSystemRepresentation ({ realpath($0, nil) }) {
    let fullUrl = URL(fileURLWithFileSystemRepresentation: rp, isDirectory: true, relativeTo: nil)
    free(rp)
    print(fullUrl.path)
}
// Output: "/Applications/Utilities"
Luminescence answered 3/11, 2016 at 12:9 Comment(4)
Excellent, that's it: "canonicalPath". Thanks a lot!Calvinna
Ups, just got the information, that this function is only available at OSX 10.12! Is there anything similar for >= 10.9?Calvinna
Yes, that's working. The function seems to work for folders only, but I can remove filename first, do the the conversion and then add it again. Thank you very much!Calvinna
@Peter71: You are welcome. It works also for files in my test. You may have to set the isDirectory argument to false.Luminescence
R
0

Note that you want to use URL wherever possible, from the NSURL documentation:

URL objects are the preferred way to refer to local files. Most objects that read data from or write data to a file have methods that accept an NSURL object instead of a pathname as the file reference.

Here’s an example of how to get all the objects from a directory:

import Foundation

let manager = FileManager.default

// Get URL for the current user’s Documents directory
// Use URL instead of path, it’s more flexible and preferred
if let documents = manager.urls(for: .documentDirectory, in: .userDomainMask).first,

  // Get an Enumerator for the paths of all the objects in the directory
  // but do not descend into directories or packages
  let directoryEnumerator = manager.enumerator(at: documents, includingPropertiesForKeys: [URLResourceKey.pathKey], options: [.skipsSubdirectoryDescendants, .skipsPackageDescendants]) {

  // iterate through the objects (files, directories, etc.) in the directory
  for path in directoryEnumerator {
    print(path)
  }
}
Rik answered 3/11, 2016 at 9:52 Comment(1)
That's exactly what I had in mind (and what I did). I'm looking for a converting function from long (explicit) to short version (only "/") without writing it by my own on string basis.Calvinna

© 2022 - 2024 — McMap. All rights reserved.