使用 Swift 的 FileManager 遍历文件夹及其子文件夹中的文件

我对编写 Swift 程序还是个新手,我正在尝试迭代文件夹中的文件。 我查看了答案 给你并试图将其翻译成 Swift 语法,但没有成功。

let fileManager = NSFileManager.defaultManager()
let enumerator:NSDirectoryEnumerator = fileManager.enumeratorAtPath(folderPath)


for element in enumerator {
//do something
}

我得到的错误是:

Type 'NSDirectoryEnumerator' does not conform to protocol 'SequenceType'

我的目标是查看包含在主文件夹中的所有子文件夹和文件,找到所有具有某个扩展名的文件,然后对它们进行处理。

58292 次浏览

使用 enumeratornextObject()方法:

while let element = enumerator?.nextObject() as? String {
if element.hasSuffix("ext") { // checks the extension
}
}

我根本无法让 pNre 的解决方案工作; while 循环从未接收到任何东西。然而,我确实遇到了这个解决方案,它适合我(在 Xcode 6 beta 6中,所以也许自从 pNre 发布了上面的答案之后,事情发生了变化?):

for url in enumerator!.allObjects {
print("\((url as! NSURL).path!)")
}

如果你得到了

‘ NSDirectoryEnumerator?’ 没有名为 ‘ nextObject’的成员错误

While 循环应该是:

while let element = enumerator?.nextObject() as? String {
// do things with element
}

这和 可选的锁链有关

更新 Swift 3:

let fileManager = FileManager()     // let fileManager = NSFileManager.defaultManager()
let en=fileManager.enumerator(atPath: the_path)   // let enumerator:NSDirectoryEnumerator = fileManager.enumeratorAtPath(folderPath)


while let element = en?.nextObject() as? String {
if element.hasSuffix("ext") {
// do something with the_path/*.ext ....
}
}

Swift 3

let fd = FileManager.default
fd.enumerator(atPath: "/Library/FileSystems")?.forEach({ (e) in
if let e = e as? String, let url = URL(string: e) {
print(url.pathExtension)
}
})

Swift3 + 绝对网址

extension FileManager {
func listFiles(path: String) -> [URL] {
let baseurl: URL = URL(fileURLWithPath: path)
var urls = [URL]()
enumerator(atPath: path)?.forEach({ (e) in
guard let s = e as? String else { return }
let relativeURL = URL(fileURLWithPath: s, relativeTo: baseurl)
let url = relativeURL.absoluteURL
urls.append(url)
})
return urls
}
}

基于 @ user3441734的代码

SWIFT 3.0

返回传递的目录及其子目录中具有扩展名的所有文件

func extractAllFile(atPath path: String, withExtension fileExtension:String) -> [String] {
let pathURL = NSURL(fileURLWithPath: path, isDirectory: true)
var allFiles: [String] = []
let fileManager = FileManager.default
let pathString = path.replacingOccurrences(of: "file:", with: "")
if let enumerator = fileManager.enumerator(atPath: pathString) {
for file in enumerator {
if #available(iOS 9.0, *) {
if let path = NSURL(fileURLWithPath: file as! String, relativeTo: pathURL as URL).path, path.hasSuffix(".\(fileExtension)"){
let fileNameArray = (path as NSString).lastPathComponent.components(separatedBy: ".")
allFiles.append(fileNameArray.first!)
}
} else {
// Fallback on earlier versions
print("Not available, #available iOS 9.0 & above")
}
}
}
return allFiles
}

现在(2017年初)强烈推荐使用-更多功能-URL 相关的 API

let fileManager = FileManager.default


do {
let resourceKeys : [URLResourceKey] = [.creationDateKey, .isDirectoryKey]
let documentsURL = try fileManager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let enumerator = FileManager.default.enumerator(at: documentsURL,
includingPropertiesForKeys: resourceKeys,
options: [.skipsHiddenFiles], errorHandler: { (url, error) -> Bool in
print("directoryEnumerator error at \(url): ", error)
return true
})!


for case let fileURL as URL in enumerator {
let resourceValues = try fileURL.resourceValues(forKeys: Set(resourceKeys))
print(fileURL.path, resourceValues.creationDate!, resourceValues.isDirectory!)
}
} catch {
print(error)
}

返回子目录中目录 + 中的所有文件

import Foundation


let path = "<some path>"


let enumerator = FileManager.default.enumerator(atPath: path)


while let filename = enumerator?.nextObject() as? String {
print(filename)
}

如果您希望明确地检查元素是文件还是子目录:

let enumerator = FileManager.default.enumerator(atPath: contentsPath);
while let element = enumerator?.nextObject() as? String {
if(enumerator?.fileAttributes?[FileAttributeKey.type] as! FileAttributeType == FileAttributeType.typeRegular){
//this is a file
}
else if(enumerator?.fileAttributes?[FileAttributeKey.type] as! FileAttributeType == FileAttributeType.typeDirectory){
//this is a sub-directory
}
}

苹果文档提到,基于 Path 的 URL 在某些方面更简单,但是文件引用 URL 的优点是,如果在应用程序运行时文件被移动或重命名,引用仍然有效。

来自“访问文件和目录”的文档:

”基于路径的 URL 更容易操作、更容易调试,通常是 NSFileManager 等类的首选。文件引用 URL 的一个优点是,在应用程序运行时,它们不像基于路径的 URL 那么脆弱。如果用户在 Finder 中移动文件,任何引用该文件的基于路径的 URL 将立即变为无效,并且必须更新到新路径。但是,只要文件移动到同一磁盘上的另一个位置,它的唯一 ID 就不会改变,任何文件引用 URL 都是有效的。”

Https://developer.apple.com/library/content/documentation/filemanagement/conceptual/filesystemprogrammingguide/accessingfilesanddirectories/accessingfilesanddirectories.html

最近在处理 url 数组时,无论它们是否是目录(例如拖放) ,都会遇到这个问题。最后以这个扩展结束在迅速4,可能是有用的

extension Sequence where Iterator.Element == URL {


var handleDir: [URL] {
var files: [URL] = []
self.forEach { u in
guard u.hasDirectoryPath else { return files.append(u.resolvingSymlinksInPath()) }
guard let dir = FileManager.default.enumerator(at: u.resolvingSymlinksInPath(), includingPropertiesForKeys: nil) else { return }
for case let url as URL in dir {
files.append(url.resolvingSymlinksInPath())
}
}
return files
}
}

避免使用引用 URL,尽管它们确实有上面提到的一些优点,但是它们会占用系统资源,如果你枚举一个大的文件系统(实际上并不是那么大) ,你的应用程序很快就会撞上系统墙,然后被 macOS 关闭。

我从前面的回答中得到的两点建议... 更加迅速和可选:

 let enumerator = FileManager.default.enumerator(atPath: folderPath)
while let element = enumerator?.nextObject() as? String {
print(element)


if let fType = enumerator?.fileAttributes?[FileAttributeKey.type] as? FileAttributeType{


switch fType{
case .typeRegular:
print("a file")
case .typeDirectory:
print("a dir")
}
}


}