Reputation: 1978
I'm learning swift and wondering what's the best way to list all files with absolute path in a directory including ones from subfolders(files only)
I tried with following, but it seems listing all contents names even folder names without full paths.
let paths = FileManager.default.subpaths(atPath: folderPath)
for p in paths! {
print p
}
}
as well as
let items = try fm.contentsOfDirectory(atPath: folderPath)
googling didn't come out with any working methods.
this is for macOS 10.14
any help is appreciated!
thanks
Upvotes: 26
Views: 15167
Reputation: 1641
FileManager
is right object
If you are using swift 5
or above could take advantage of AsyncStream
. Below a simple 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)
}
}
Upvotes: 8
Reputation: 285240
FileManager
has also a method for a deep search: enumerator(at:includingPropertiesForKeys:options:errorHandler:)
To get only the files you have to iterate the enumerator and filter the files
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)
}
It's highly recommended to use URLs rather than string paths.
Upvotes: 59