Itere a través de archivos en una carpeta y sus subcarpetas usando el FileManager de Swift
cocoa nsfilemanager (13)
Swift3 + URL absolutas
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
}
}
Basado en el código de @ user3441734
Soy bastante nuevo en la programación de Swift y estoy tratando de iterar a través de los archivos en una carpeta. Eché un vistazo a la respuesta e intenté traducirla a la sintaxis de Swift, pero no funcionó.
let fileManager = NSFileManager.defaultManager()
let enumerator:NSDirectoryEnumerator = fileManager.enumeratorAtPath(folderPath)
for element in enumerator {
//do something
}
el error que obtengo es:
Type ''NSDirectoryEnumerator'' does not conform to protocol ''SequenceType''
Mi objetivo es mirar todas las subcarpetas y archivos contenidos en la carpeta principal y encontrar todos los archivos con una cierta extensión para luego hacer algo con ellos.
Actualizando para 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 ....
}
}
Agregando a la respuesta de vadian: Apple menciona que las URL basadas en rutas son más simples de alguna manera, sin embargo, las URL de referencia de archivos tienen la ventaja de que la referencia sigue siendo válida si el archivo se mueve o cambia de nombre mientras se ejecuta su aplicación.
De la documentación para "Acceso a archivos y directorios":
"Las URL basadas en rutas son más fáciles de manipular, más fáciles de depurar y generalmente son preferidas por clases como NSFileManager. Una ventaja de las URL de referencia de archivos es que son menos frágiles que las URL basadas en rutas mientras la aplicación se está ejecutando. mueve un archivo en el Finder, cualquier URL basada en ruta que haga referencia al archivo se vuelve inmediatamente inválida y debe actualizarse a la nueva ruta. Sin embargo, mientras el archivo se mueva a otra ubicación en el mismo disco, su ID única no cambio y cualquier URL de referencia de archivo sigue siendo válida ".
En caso de que esté obteniendo el
''NSDirectoryEnumerator?'' no tiene un miembro llamado error ''nextObject''
el ciclo while debería ser:
while let element = enumerator?.nextObject() as? String {
// do things with element
}
Tiene algo que ver con el encadenamiento opcional
En la actualidad (principios de 2017), es muy recomendable utilizar la API relacionada con URL, más versátil.
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)
}
Evite las URL de referencia, aunque tienen algunas ventajas como las indicadas anteriormente, consumen recursos del sistema y si está enumerando un gran sistema de archivos (no tan grande en realidad), su aplicación llegará a la pared del sistema rápidamente y se cerrará con macOS.
No pude lograr que la solución de pNre funcionara; el bucle while nunca recibió nada. Sin embargo, me encontré con esta solución que funciona para mí (en Xcode 6 beta 6, así que tal vez las cosas hayan cambiado desde que pNre publicó la respuesta anterior):
for url in enumerator!.allObjects {
print("/((url as! NSURL).path!)")
}
Recientemente ha tenido problemas con esto al manejar una matriz de URL, ya sea que se trate de un directorio o no (por ejemplo, arrastrar y soltar). Terminó con esta extensión en swift 4, puede ser de utilidad
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
}
}
Si desea verificar categóricamente si un elemento es un archivo o un subdirectorio:
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
}
}
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)
}
})
Use el método de enumerator
nextObject()
:
while let element = enumerator?.nextObject() as? String {
if element.hasSuffix("ext") { // checks the extension
}
}
devuelve todos los archivos en el directorio
Swift 3
let fileNames = try! FileManager.default.contentsOfDirectory(atPath: "/Volumes/Seagate/Path/")
for fileName in fileNames {
print(fileName)
}
SWIFT 3.0
Devuelve todos los archivos con extensión en el Directorio pasado y sus subdirectorios
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
}