Iterate through files in a folder and its subfolders using Swift's FileManager

56,504

Solution 1

Use the nextObject() method of enumerator:

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

Solution 2

Nowadays (early 2017) it's highly recommended to use the – more versatile – URL related 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)
}

Solution 3

I couldn't get pNre's solution to work at all; the while loop just never received anything. However, I did come across this solution which works for me (in Xcode 6 beta 6, so perhaps things have changed since pNre posted the above answer?):

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

Solution 4

Swift3 + absolute urls

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

Based on code from @user3441734

Solution 5

returns all files in a directory + in subdirectories

import Foundation

let path = "<some path>"

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

while let filename = enumerator?.nextObject() as? String {
        print(filename)
}
Share:
56,504

Related videos on Youtube

Iacopo Boccalari
Author by

Iacopo Boccalari

Updated on June 23, 2021

Comments

  • Iacopo Boccalari
    Iacopo Boccalari almost 3 years

    I'm quite new to programming a Swift and I'm trying to iterate through the files in a folder. I took a look at the answer here and tried to translate it to Swift syntax, but didn't succeed.

    let fileManager = NSFileManager.defaultManager()
    let enumerator:NSDirectoryEnumerator = fileManager.enumeratorAtPath(folderPath)
    
    for element in enumerator {
        //do something
    }
    

    the error I get is:

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

    My aim is to look at all the subfolders and files contained into the main folder and find all the files with a certain extension to then do something with them.

  • Bjorn
    Bjorn over 9 years
    Couldn't get this to work without optional chaining as per user1398498's answer below.
  • nhgrif
    nhgrif about 8 years
    Having just tried this out, I got nothing but an infinite loop and had to go with Rainier's approach roughly.
  • qwerty_so
    qwerty_so almost 8 years
    Funny that this solution has so few up-votes since it has a fairly more easy syntax than the current favorite.
  • Boris Suvorov
    Boris Suvorov over 7 years
    the reason why it has votes because it relies on forced unwrapping of enumerator (enumerator!) as opposed to enumerator? in top voted answer.
  • qwerty_so
    qwerty_so over 7 years
    Very strange that a rather crude while is favored over the dense for solution. (Oh, I see I already commented on the other solution similarly - anyway)
  • Rodrigo Gonzalez
    Rodrigo Gonzalez about 7 years
    For those who use enumerator(at:, includingPropertiesForKeys:, options:) take into account that the element is actually a URL not a String, so if you use that code it will return nothing. while let element = enumerator?.nextObject() as? URL {...}
  • ATutorMe
    ATutorMe over 6 years
    When I used this code I found that directories/files with spaces in the path were ignored. Any idea why this happens? I then tried @vadian's code and it works as expected.
  • vomi
    vomi over 6 years
    It won't go inside subdirectories nor get hidden files nor follow symbolic links
  • green_knight
    green_knight about 6 years
    Thank you for your thoroughness. (I had no luck at all with the path-typed version, since myURL.absolutePath is not a valid string-based path for the purposes of NSFileEnumerator and does not create a valid enumerator). For the list of URLResourceKeys, look at developer.apple.com/documentation/foundation/urlresourcekey
  • Abhi Beckert
    Abhi Beckert almost 6 years
    Beware this is unusable large directories - it can hang for minutes.
  • Buddhisthead
    Buddhisthead over 5 years
    This is a good example of how to execute a deep search and worked great for me. Thank you for the nice contribution.
  • ikel
    ikel over 4 years
    how do we get full path instead of file names?
  • Mark Perkins
    Mark Perkins over 4 years
    Stop force unwrapping.
  • midtownguru
    midtownguru over 4 years
    What kind of path do you use? In my case, I have "mydir" directory in the xcode project. When I use let path = "mydir", nothing happends. I'using swift 5.
  • midtownguru
    midtownguru over 4 years
    It's a full path. Is there a way to use a relative path so that it can be contained in the project folder?
  • arango_86
    arango_86 about 4 years
    Good reference. I found it from the below link too. developer.apple.com/documentation/foundation/filemanager/…
  • TruMan1
    TruMan1 almost 4 years
    Doesn't answer the question, this should be more of a comment than an answer.
  • ChrisH
    ChrisH over 3 years
    This is THE most useful entry here as it highlights picking apart the entries by dir and file types. That seems to be a very forgotten part of functionality like this.
  • shuna
    shuna almost 3 years
    This code is very helpful. But I want to get progress of traversing files at least first sub level directories in root folder (Of course, I understand that we cannot get the exact total number of files until we have enumerated all of them. For this reason, it would be nice to know the acquisition progress of "at least the first sub-level".). Is there any way to get the progress?
  • ingconti
    ingconti almost 2 years
    the real reason is that more an more Apple APIs DO want urls. (se for example all path-related calls)