Swift 2 iOS - get file list sorted by creation date - more concise solution?
Swift 5.0 Uses Filter and Sort by ModificationDate
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
guard let directoryURL = URL(string: paths.path) else {return}
do {
let contents = try
FileManager.default.contentsOfDirectory(at: directoryURL,
includingPropertiesForKeys:[.contentModificationDateKey],
options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants])
.filter { $0.lastPathComponent.hasSuffix(".swift") }
.sorted(by: {
let date0 = try $0.promisedItemResourceValues(forKeys:[.contentModificationDateKey]).contentModificationDate!
let date1 = try $1.promisedItemResourceValues(forKeys:[.contentModificationDateKey]).contentModificationDate!
return date0.compare(date1) == .orderedDescending
})
// Print results
for item in contents {
guard let t = try? item.promisedItemResourceValues(forKeys:[.contentModificationDateKey]).contentModificationDate
else {return}
print ("\(t) \(item.lastPathComponent)")
}
} catch {
print (error)
}
A possible solution:
if let urlArray = try? NSFileManager.defaultManager().contentsOfDirectoryAtURL(directory,
includingPropertiesForKeys: properties, options:.SkipsHiddenFiles) {
return urlArray.map { url -> (String, NSTimeInterval) in
var lastModified : AnyObject?
_ = try? url.getResourceValue(&lastModified, forKey: NSURLContentModificationDateKey)
return (url.lastPathComponent!, lastModified?.timeIntervalSinceReferenceDate ?? 0)
}
.sort({ $0.1 > $1.1 }) // sort descending modification dates
.map { $0.0 } // extract file names
} else {
return nil
}
The array of URLs is mapped to an array of (lastPathComponent, lastModificationDate)
tuples first, then sorted according to the
last modification date, and finally the path name extracted.
The attributesDictionary
can be avoided by using
getResourceValue(_ : forKey)
to retrieve only the last modification date.
Update for Swift 3:
let directory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
if let urlArray = try? FileManager.default.contentsOfDirectory(at: directory,
includingPropertiesForKeys: [.contentModificationDateKey],
options:.skipsHiddenFiles) {
return urlArray.map { url in
(url.lastPathComponent, (try? url.resourceValues(forKeys: [.contentModificationDateKey]))?.contentModificationDate ?? Date.distantPast)
}
.sorted(by: { $0.1 > $1.1 }) // sort descending modification dates
.map { $0.0 } // extract file names
} else {
return nil
}
Swift 3 Code With Complete Solution: Based on @ingconti's answer. This method return list of item names from provided URL path.
func filesSortedList(atPath: URL) -> [String]? {
var fileNames = [String]()
let keys = [URLResourceKey.contentModificationDateKey]
guard let fullPaths = try? FileManager.default.contentsOfDirectory(at: atPath, includingPropertiesForKeys:keys, options: FileManager.DirectoryEnumerationOptions.skipsHiddenFiles) else {
return [""]
}
let orderedFullPaths = fullPaths.sorted(by: { (url1: URL, url2: URL) -> Bool in
do {
let values1 = try url1.resourceValues(forKeys: [.creationDateKey, .contentModificationDateKey])
let values2 = try url2.resourceValues(forKeys: [.creationDateKey, .contentModificationDateKey])
if let date1 = values1.creationDate, let date2 = values2.creationDate {
//if let date1 = values1.contentModificationDate, let date2 = values2.contentModificationDate {
return date1.compare(date2) == ComparisonResult.orderedDescending
}
} catch _{
}
return true
})
for fileName in orderedFullPaths {
do {
let values = try fileName.resourceValues(forKeys: [.creationDateKey, .contentModificationDateKey])
if let date = values.creationDate{
//let date : Date? = values.contentModificationDate
print(fileName.lastPathComponent, " ", date)
let theFileName = fileName.lastPathComponent
fileNames.append(theFileName)
}
}
catch _{
}
}
return fileNames
}
Swift 5.0. Simple extension based on the previous answers:
extension FileManager {
enum ContentDate {
case created, modified, accessed
var resourceKey: URLResourceKey {
switch self {
case .created: return .creationDateKey
case .modified: return .contentModificationDateKey
case .accessed: return .contentAccessDateKey
}
}
}
func contentsOfDirectory(atURL url: URL, sortedBy: ContentDate, ascending: Bool = true, options: FileManager.DirectoryEnumerationOptions = [.skipsHiddenFiles]) throws -> [String]? {
let key = sortedBy.resourceKey
var files = try contentsOfDirectory(at: url, includingPropertiesForKeys: [key], options: options)
try files.sort {
let values1 = try $0.resourceValues(forKeys: [key])
let values2 = try $1.resourceValues(forKeys: [key])
if let date1 = values1.allValues.first?.value as? Date, let date2 = values2.allValues.first?.value as? Date {
return date1.compare(date2) == (ascending ? .orderedAscending : .orderedDescending)
}
return true
}
return files.map { $0.lastPathComponent }
}
}