FileManager DirectoryEnumerator and skipDescendants issue

I'm trying to use the example code https://developer.apple.com/documentation/foundation/filemanager/2765464-enumerator to exclude a sub directory, but the .skipDescendants doesn't seem to do what I expect. Should this work? I want to ignore everything in the __CYCLES folder inside topLevelFolder. But those paths are listed along with all the other files/folders. I never see "Skipping Cycles" in my output.

import Foundation

let rootPath = "/Volumes/volumename/topLevelFolder"
let topLevelFolderURL = URL(fileURLWithPath: rootPath)


let localFileManager = FileManager()

let resourceKeys = Set<URLResourceKey>([.nameKey, .isDirectoryKey, .fileSizeKey])
let directoryEnumerator = localFileManager.enumerator(at: topLevelFolderURL, includingPropertiesForKeys: Array(resourceKeys), options: [.skipsHiddenFiles, .skipsPackageDescendants])!

for case let fileURL as URL in directoryEnumerator {
    guard let resourceValues = try? fileURL.resourceValues(forKeys: resourceKeys),
          let isDirectory = resourceValues.isDirectory,
          let name = resourceValues.name,
          let size = resourceValues.fileSize
    else {
        continue
    }
    
    if isDirectory {
        if name == "__CYCLES" {
            directoryEnumerator.skipDescendants()
            print("Skipping Cycles")
        }
    } else {
        print("\(fileURL.path) = \(size)")
    }
}
Answered by DTS Engineer in 809020022

The problem is this line:

let size = resourceValues.fileSize

A directory has no fileSize property, so in the directory case the guard fails and you always run the continue. That means that this test never succeeds:

if isDirectory {

so you never call skipDescendants().

And yes, I did have to run your code in order to spot this. It’s remarkably subtle for such a small program!

Share and Enjoy

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

Accepted Answer

The problem is this line:

let size = resourceValues.fileSize

A directory has no fileSize property, so in the directory case the guard fails and you always run the continue. That means that this test never succeeds:

if isDirectory {

so you never call skipDescendants().

And yes, I did have to run your code in order to spot this. It’s remarkably subtle for such a small program!

Share and Enjoy

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

THANK YOU! That's a great catch. I should have focused on the few differences from the sample.

FileManager DirectoryEnumerator and skipDescendants issue
 
 
Q