FileManager.enumerator and URL problem

I have the following pseudo code:

func load(at packageURL: URL) {
    let realPackageURL = packageURL.resolvingSymlinksInPath()

    guard let it = fileMan.enumerator(at: realPackageURL)
    for case let fileURL as URL in it {
        print(fileURL)
        // Get filename relative to package root directory
        let relativeFileName = String(filePath.suffix(filePath.count - packagePath.count))
    }
}

When called with "file:///tmp/some.app", the enumerated fileURL is actually

file:///private/tmp/GIMP.app/Contents/

packageURL.resolvingSymlinksInPath() actually does nothing, I assume /tmp is a hard link.

This makes it impossible to get a correct relative path. Is there any remedy for this?

Answered by imneo in 776848022

Unfortunately, contentsOfDirectory(at:) suffers the same problem as the enumerator.

But anyway, I devised a workaround that leads to a little more memory footprint.

var fileList = [URL]()
for case let fileURL as URL in it {
    fileList.append(fileURL)
}

// Sort by length so that the shortest comes first
fileList.sort { $0.relativePath.count < $1.relativePath.count }
// The shortest path without last component is the root path.
let packageRoot = fileList[0].url.deletingLastPathComponent().path

I recommend that you use contentsOfDirectory(at:includingPropertiesForKeys:options:). This has a couple of benefits:

  • It lets you specify the properties to preload, which can speed things up a lot.

  • Relevant to this case, it returns URLs that are relative to the directory URL you pass in, which eliminates this question.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Accepted Answer

Unfortunately, contentsOfDirectory(at:) suffers the same problem as the enumerator.

But anyway, I devised a workaround that leads to a little more memory footprint.

var fileList = [URL]()
for case let fileURL as URL in it {
    fileList.append(fileURL)
}

// Sort by length so that the shortest comes first
fileList.sort { $0.relativePath.count < $1.relativePath.count }
// The shortest path without last component is the root path.
let packageRoot = fileList[0].url.deletingLastPathComponent().path
FileManager.enumerator and URL problem
 
 
Q