web-dev-qa-db-fra.com

Parcourez les fichiers d'un dossier et de ses sous-dossiers à l'aide de FileManager de Swift

Je suis assez nouveau pour programmer un Swift et j'essaye de parcourir les fichiers d'un dossier ..__ J'ai jeté un coup d'œil à la réponse ici et j'ai essayé de le traduire en syntaxe Swift, mais je ne l'ai pas fait. t réussir.

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

for element in enumerator {
    //do something
}

l'erreur que je reçois est:

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

Mon but est d’examiner tous les sous-dossiers et fichiers contenus dans le dossier principal et de trouver tous les fichiers avec une certaine extension pour ensuite faire quelque chose avec eux.

59
Iacopo Boccalari

Utilisez la méthode nextObject() de enumerator:

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

De nos jours (début 2017), il est fortement recommandé d'utiliser l'API - plus polyvalente - liée aux URL

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)
}
48
vadian

Je ne pouvais pas faire fonctionner la solution de pNre; la boucle while n'a tout simplement jamais rien reçu. Cependant, je suis tombé sur cette solution qui me convient (dans Xcode 6 beta 6, les choses ont peut-être changé depuis que pNre a posté la réponse ci-dessus?):

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

renvoie tous les fichiers d'un répertoire

Swift 3

let fileNames = try! FileManager.default.contentsOfDirectory(atPath: "/Volumes/Seagate/Path/")

for fileName in fileNames {

    print(fileName)

}
5
Alex Shubin

Au cas où vous obtenez le 

'NSDirectoryEnumerator?' n'a pas de membre nommé 'nextObject' error

la boucle while devrait être:

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

Cela a quelque chose à voir avec chaînage optionnel

5
user1398498

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)
    }
})
5
user3441734

Swift 3.0

Renvoie tous les fichiers avec l'extension du répertoire passé et de ses sous-répertoires.

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
}
4
Ranjith

Swift3 + urls absolues

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
    }
}

Basé sur le code de @ user3441734

3
neoneye

Mise à jour pour 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 ....
    }
}
2
dawg

En ajoutant à la réponse de vadian - les documents Apple mentionnent que les URL basées sur le chemin sont plus simples à certains égards. Toutefois, les URL de référence de fichier ont l'avantage de conserver la validité de la référence si le fichier est déplacé ou renommé pendant l'exécution de votre application.

Dans la documentation "Accès aux fichiers et répertoires":

"Les URL basées sur les chemins sont plus faciles à manipuler, à déboguer et sont généralement préférées par des classes telles que NSFileManager. Un avantage des URL de référence de fichier est qu'elles sont moins fragiles que les URL basées sur des chemins lorsque votre application est en cours d'exécution. Si l'utilisateur déplace un fichier dans le Finder, toute URL basée sur un chemin qui fait référence au fichier devient immédiatement invalide et doit être mise à jour dans le nouveau chemin. Toutefois, tant que le fichier est déplacé vers un autre emplacement du même disque, son ID unique ne change et toute URL de référence de fichier reste valide. "

https://developer.Apple.com/library/content/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/AccessingFilesandDirectories/AccessingFilesandDirectories.html

1
dougzilla

Évitez les URL de référence. Bien qu'elles présentent certains des avantages mentionnés ci-dessus, elles consomment des ressources système. Si vous énumérez un système de fichiers volumineux (pas si grand que cela en soit), votre application heurtera rapidement le mur du système et sera arrêtée par macOS.

0
David Hitchen

Récemment, elle a eu du mal à gérer cela en manipulant un tableau d’URL, qu’il s’agisse d’un répertoire ou non (par exemple, glisser-déposer). Terminé avec cette extension dans Swift 4, peut être utile

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
    }
}
0
Joe Maher

mes deux cents de réponses précédentes .. plus rapide et avec les optionnels:

 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")
            }
        }

    }
0
ingconti

Si vous voulez vérifier catégoriquement si un élément est un fichier ou un sous-répertoire:

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
    }
}
0
Chris Amelinckx