Iterating through files in a folder and its subfolders using Swift FileManager

I am new to Swift programming and I am trying to iterate files in a folder. I looked at the answer here and tried to translate it into Swift syntax, but failed.

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

I get an error:

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

My goal is to look at all the subfolders and files contained in the main folder, and find all the files with a specific extension, then to do something with them.

+65
cocoa swift nsfilemanager
Aug 13 '14 at 11:31
source share
14 answers

Use the nextObject() enumerator method:

 while let element = enumerator?.nextObject() as? String { if element.hasSuffix("ext") { // checks the extension } } 
+73
Aug 13 '14 at 11:40
source share

Currently (at the beginning of 2017), it is highly recommended to use a more universal 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) } 
+52
Feb 01 '17 at 12:01
source share

I could not get the pNre solution to work at all; the while loop has never received anything. However, I came across this solution that works for me (in Xcode 6 beta 6, so maybe the situation has changed since pNre posted the answer above?):

 for url in enumerator!.allObjects { print("\((url as! NSURL).path!)") } 
+18
Sep 08 '14 at 7:10
source share

returns all files in the + 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) } 
+7
May 05 '17 at 18:43
source share

If you get

"NSDirectoryEnumerator?" does not have a name named 'nextObject' error

while loop should be:

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

This is due to an optional chain.

+5
Oct 22 '14 at 8:19
source share

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
Nov 09 '16 at 22:07
source share

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

+5
Nov 29 '16 at 12:35
source share

SWIFT 3.0

Returns all files with the extension in the transferred directory and its subdirectories

 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
Feb 01 '17 at 11:50
source share

Update for 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
Nov 09 '16 at 21:03
source share

my two cents from earlier anwers .. faster and with extra:

  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") } } } 
+2
Apr 15 '19 at 20:47
source share

In addition to the unexpected answer, Apple's documentation mentions that path-based URLs are in some ways simpler, however file link URLs have the advantage that the link remains valid if the file is moved or renamed while the application is running.

From the documentation "Access to files and directories":

"Path-based URLs are easier to manipulate, easier to debug, and are generally preferred over classes like NSFileManager. The advantage of file URLs is that they are less fragile than path-based URLs when your application is running. If the user moves the file to Finder, any path-based URLs that link to the file immediately become invalid and need to be updated to the new path. However, while the file is moved to another location on the same drive, its unique identifier is not changed Th, and any references to the files remain valid. "

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

+1
Jan 13 '18 at 23:36
source share

If you want to categorically check whether an item is a file or a subdirectory:

 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
Sep 07 '17 at 3:32 on
source share

I recently struggled with this when processing an array of URLs, whether it be a directory or not (for example, drag and drop). Ends with this extension in Swift 4, may be useful

 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
Feb 16 '18 at 3:53
source share

Avoid link URLs, although they have some advantages, as mentioned above, they consume system resources, and if you list a large file system (in fact, not so large), your application will quickly hit the system wall and shut down using macOS .

0
Apr 12 '18 at 18:59
source share



All Articles