使用Swift递归列出文件夹中的所有文件

20

我正在学习Swift,并想知道以一种最佳的方式如何列出一个目录中所有文件的绝对路径,包括子文件夹中的文件(仅文件)

我尝试了以下方法,但它似乎只列出所有内容的名称,而不是带有完整路径的文件名,甚至还有文件夹名。

let paths = FileManager.default.subpaths(atPath: folderPath)
    for p in paths! {
       print p
    }
}

以及

let items = try fm.contentsOfDirectory(atPath: folderPath)

通过谷歌搜索没有找到任何可行的方法。

这是针对 macOS 10.14 的。

非常感谢你的帮助!

谢谢

2个回答

46

FileManager 还有一个进行深度搜索的方法:enumerator(at:includingPropertiesForKeys:options:errorHandler:)

要获取仅文件,您需要迭代枚举器并过滤文件。

let url = URL(fileURLWithPath: "/path/to/directory")
var files = [URL]()
if let enumerator = FileManager.default.enumerator(at: url, includingPropertiesForKeys: [.isRegularFileKey], options: [.skipsHiddenFiles, .skipsPackageDescendants]) {
    for case let fileURL as URL in enumerator {
        do {
            let fileAttributes = try fileURL.resourceValues(forKeys:[.isRegularFileKey])
            if fileAttributes.isRegularFile! {
                files.append(fileURL)
            }
        } catch { print(error, fileURL) }
    }
    print(files)
}

强烈建议使用URL而不是字符串路径。


得到的变量 files = URL,无法使用参数列表“()”调用函数类型值。 - ikel
好的,没问题,它在 Playground 中有效,我将 URL 更改为 NSURL,然后它就可以了,非常感谢。 - ikel
嗯,我得到的文件路径包含了 %20,这个我不能使用,有什么方法可以获取真实的文件路径吗? - ikel
1
var files = [String]() and files.append(fileURL.path) - vadian
虽然这里接受的答案是最好的,因为它使用了URL,但在此要考虑的一个类似且相关的想法(链接在末尾)。它允许区分文件或文件夹以及包括符号链接在内的“其他”类型的文件。在控制台中轻松地print(element)也很简洁。如果使用字符串数组,我还建议使用elements.sort()。https://dev59.com/r18e5IYBdhLWcg3w2dcD#55697010 - bubbaspike
显示剩余3条评论

5

FileManager 是正确的对象

如果您正在使用 swift 5 或更高版本,可以利用 AsyncStream。以下是一个简单的 Playground

import Foundation
import Combine

// Recursive iteration     
func walkDirectory(at url: URL, options: FileManager.DirectoryEnumerationOptions ) -> AsyncStream<URL> {
    AsyncStream { continuation in
        Task {
            let enumerator = FileManager.default.enumerator(at: url, includingPropertiesForKeys: nil, options: options)
                
            while let fileURL = enumerator?.nextObject() as? URL {
                if fileURL.hasDirectoryPath {
                    for await item in walkDirectory(at: fileURL, options: options) {
                        continuation.yield(item)
                    }
                } else {
                    continuation.yield( fileURL )
                }
            }
            continuation.finish()
        }
    }
}


// use it     
let path = URL( string: "<your path>" )

let options: FileManager.DirectoryEnumerationOptions = [.skipsHiddenFiles, .skipsPackageDescendants]
    
Task {
        
    let swiftFiles = walkDirectory(at: path!, options: options).filter {
        $0.pathExtension == "swift"
    }

    for await item in swiftFiles {
        print(item.lastPathComponent)
    }
        
}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接