Swift 2 iOS - 获取按创建日期排序的文件列表 - 更简洁的解决方案?
Swift 2 iOS - get file list sorted by creation date - more concise solution?
在我有效的代码中,我返回一个 [String]?
,其中包含存储在 /Documents/
中的文件名称 (lastPathComponent
) - 按上次修改日期排序。
我相信我可能使用了太多的步骤,我正在寻找有关如何减少代码的建议。
为了达到当前所需的结果 - 我正在创建两个中间词典:var attributesDictionary: [String : AnyObject]?
和 var urlDictionary = [NSURL:NSDate]()
。循环初始 [NSURL]
我使用两个步骤 - .resourceValuesForKeys
初始化 attributesDictionary
。然后我填充 urlDictionary
以便它包含 URL 和键的值 NSURLContentModificationDateKey
.
我相当肯定应该有一种方法可以在不创建 urlDictionary
和 attributesDictionary
并且不需要循环的情况下实现这个结果。也许直接来自 urlArray
。这是我当前的代码:
编辑:正如 Arthur Gevorkyan 在第一条评论中指出的那样,do{}
不是必需的。
func getFileList() -> [String]? {
let directory = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let properties = [NSURLLocalizedNameKey, NSURLCreationDateKey, NSURLContentModificationDateKey, NSURLLocalizedTypeDescriptionKey]
// no catch required - contentsOfDirectoryAtURL returns nil if there is an error
if let urlArray = try? NSFileManager.defaultManager().contentsOfDirectoryAtURL(directory, includingPropertiesForKeys: properties, options:NSDirectoryEnumerationOptions.SkipsHiddenFiles) {
var attributesDictionary: [String:AnyObject]?
var dateLastModified: NSDate
var urlDictionary = [NSURL:NSDate]()
for URLs in urlArray {
// no catch required - resourceValuesForKeys returns nil if there is an error
attributesDictionary = try? URLs.resourceValuesForKeys(properties)
dateLastModified = attributesDictionary?[NSURLContentModificationDateKey] as! NSDate
urlDictionary[URLs] = dateLastModified
}
// this approach to sort is used because NSDate cannot be directly compared with </>
return urlDictionary.filter{[=12=] != nil}.sort{[=12=].1.compare(.1) == NSComparisonResult.OrderedDescending }.map{[=12=].0}.map{[=12=].lastPathComponent!}
} else {
return nil
}
}
可能的解决方案:
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({ [=10=].1 > .1 }) // sort descending modification dates
.map { [=10=].0 } // extract file names
} else {
return nil
}
URL 数组首先映射到 (lastPathComponent, lastModificationDate)
元组数组,然后根据
最后修改日期,最后提取的路径名。
attributesDictionary
可以通过使用来避免
getResourceValue(_ : forKey)
仅检索最后修改日期。
Swift3 的更新:
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: { [=11=].1 > .1 }) // sort descending modification dates
.map { [=11=].0 } // extract file names
} else {
return nil
}
return urlDictionary.filter{[=10=] != nil}.sort{[=10=].1.compare(.1) == NSComparisonResult.OrderedDescending }.map{[=10=].0}.map{[=10=].lastPathComponent!}
绝对是一个矫枉过正的代码行 :)
您可以使用 NSFileManager 的另一种方法跳过几个 filter/map 步骤:
func contentsOfDirectoryAtPath(_ path: String) throws -> [String]
和
func attributesOfItemAtPath(_ path: String) throws -> [String : AnyObject].
最后,你会得到与你已经完成的相同的东西。我觉得你的代码有点复杂,但是方法很好。
Swift3,iOS10
// MARK: - String
extension String {
func stringByAppendingPathComponent(path: String) -> String {
let nsSt = self as NSString
return nsSt.appendingPathComponent(path)
}
}
// MARK: - File manager
let fileManagerController = FileManager.default
// MARK: - Application Document Directory
// NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] return an array of String, we will catch just the first item from array
let applicationDocumentsDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
// MARK: - File path
// Combined with helpers from String extension
let filePath = applicationDocumentsDirectory.stringByAppendingPathComponent(path: name)
do {
let atributes = try fileManagerController.attributesOfItem(atPath: filePath)
// File creation date
if let fileDate = atributes[FileAttributeKey.creationDate] as? Date {
// fileDate has a String value
print(fileDate)
// Will print a creation date of file
}
} catch let error as NSError {
print("Failure to know creation date \(error.description)")
}
Swift 3.0 塞拉利昂 10.12
获取按日期排序的数组(创建或修改):
func enumAndSortFilesAt(path: String){
let fm = FileManager.default
let url = URL(fileURLWithPath: path)
let optionMask: FileManager.DirectoryEnumerationOptions = [
.skipsHiddenFiles
]
let keys = [URLResourceKey.contentModificationDateKey]
guard let files = try? fm.contentsOfDirectory(at: url,
includingPropertiesForKeys : keys,
options: optionMask ) else {
return
}
let ordered = files.sorted { ( u1: URL, u2: URL) -> Bool in
do{
let values1 = try u1.resourceValues(forKeys: [.creationDateKey, .contentModificationDateKey])
let values2 = try u2.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.orderedAscending
}
}catch _{
}
return true
}
for f in ordered {
do {
let values = try f.resourceValues(forKeys: [.creationDateKey, .contentModificationDateKey])
if let date = values.creationDate{
//let date : Date? = values.contentModificationDate
print(f.lastPathComponent, " ", date)
}
}
catch _{
}
}
}
Swift 3 完整解决方案代码:
基于@ingconti 的回答。此方法 return 提供的 URL 路径中的项目名称列表。
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。基于之前答案的简单扩展:
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 [=10=].resourceValues(forKeys: [key])
let values2 = try .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 { [=10=].lastPathComponent }
}
}
Swift 5.0 使用按修改日期筛选和排序
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 { [=10=].lastPathComponent.hasSuffix(".swift") }
.sorted(by: {
let date0 = try [=10=].promisedItemResourceValues(forKeys:[.contentModificationDateKey]).contentModificationDate!
let date1 = try .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)
}
在我有效的代码中,我返回一个 [String]?
,其中包含存储在 /Documents/
中的文件名称 (lastPathComponent
) - 按上次修改日期排序。
我相信我可能使用了太多的步骤,我正在寻找有关如何减少代码的建议。
为了达到当前所需的结果 - 我正在创建两个中间词典:var attributesDictionary: [String : AnyObject]?
和 var urlDictionary = [NSURL:NSDate]()
。循环初始 [NSURL]
我使用两个步骤 - .resourceValuesForKeys
初始化 attributesDictionary
。然后我填充 urlDictionary
以便它包含 URL 和键的值 NSURLContentModificationDateKey
.
我相当肯定应该有一种方法可以在不创建 urlDictionary
和 attributesDictionary
并且不需要循环的情况下实现这个结果。也许直接来自 urlArray
。这是我当前的代码:
编辑:正如 Arthur Gevorkyan 在第一条评论中指出的那样,do{}
不是必需的。
func getFileList() -> [String]? {
let directory = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let properties = [NSURLLocalizedNameKey, NSURLCreationDateKey, NSURLContentModificationDateKey, NSURLLocalizedTypeDescriptionKey]
// no catch required - contentsOfDirectoryAtURL returns nil if there is an error
if let urlArray = try? NSFileManager.defaultManager().contentsOfDirectoryAtURL(directory, includingPropertiesForKeys: properties, options:NSDirectoryEnumerationOptions.SkipsHiddenFiles) {
var attributesDictionary: [String:AnyObject]?
var dateLastModified: NSDate
var urlDictionary = [NSURL:NSDate]()
for URLs in urlArray {
// no catch required - resourceValuesForKeys returns nil if there is an error
attributesDictionary = try? URLs.resourceValuesForKeys(properties)
dateLastModified = attributesDictionary?[NSURLContentModificationDateKey] as! NSDate
urlDictionary[URLs] = dateLastModified
}
// this approach to sort is used because NSDate cannot be directly compared with </>
return urlDictionary.filter{[=12=] != nil}.sort{[=12=].1.compare(.1) == NSComparisonResult.OrderedDescending }.map{[=12=].0}.map{[=12=].lastPathComponent!}
} else {
return nil
}
}
可能的解决方案:
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({ [=10=].1 > .1 }) // sort descending modification dates
.map { [=10=].0 } // extract file names
} else {
return nil
}
URL 数组首先映射到 (lastPathComponent, lastModificationDate)
元组数组,然后根据
最后修改日期,最后提取的路径名。
attributesDictionary
可以通过使用来避免
getResourceValue(_ : forKey)
仅检索最后修改日期。
Swift3 的更新:
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: { [=11=].1 > .1 }) // sort descending modification dates
.map { [=11=].0 } // extract file names
} else {
return nil
}
return urlDictionary.filter{[=10=] != nil}.sort{[=10=].1.compare(.1) == NSComparisonResult.OrderedDescending }.map{[=10=].0}.map{[=10=].lastPathComponent!}
绝对是一个矫枉过正的代码行 :) 您可以使用 NSFileManager 的另一种方法跳过几个 filter/map 步骤:
func contentsOfDirectoryAtPath(_ path: String) throws -> [String]
和
func attributesOfItemAtPath(_ path: String) throws -> [String : AnyObject].
最后,你会得到与你已经完成的相同的东西。我觉得你的代码有点复杂,但是方法很好。
Swift3,iOS10
// MARK: - String
extension String {
func stringByAppendingPathComponent(path: String) -> String {
let nsSt = self as NSString
return nsSt.appendingPathComponent(path)
}
}
// MARK: - File manager
let fileManagerController = FileManager.default
// MARK: - Application Document Directory
// NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] return an array of String, we will catch just the first item from array
let applicationDocumentsDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
// MARK: - File path
// Combined with helpers from String extension
let filePath = applicationDocumentsDirectory.stringByAppendingPathComponent(path: name)
do {
let atributes = try fileManagerController.attributesOfItem(atPath: filePath)
// File creation date
if let fileDate = atributes[FileAttributeKey.creationDate] as? Date {
// fileDate has a String value
print(fileDate)
// Will print a creation date of file
}
} catch let error as NSError {
print("Failure to know creation date \(error.description)")
}
Swift 3.0 塞拉利昂 10.12
获取按日期排序的数组(创建或修改):
func enumAndSortFilesAt(path: String){
let fm = FileManager.default
let url = URL(fileURLWithPath: path)
let optionMask: FileManager.DirectoryEnumerationOptions = [
.skipsHiddenFiles
]
let keys = [URLResourceKey.contentModificationDateKey]
guard let files = try? fm.contentsOfDirectory(at: url,
includingPropertiesForKeys : keys,
options: optionMask ) else {
return
}
let ordered = files.sorted { ( u1: URL, u2: URL) -> Bool in
do{
let values1 = try u1.resourceValues(forKeys: [.creationDateKey, .contentModificationDateKey])
let values2 = try u2.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.orderedAscending
}
}catch _{
}
return true
}
for f in ordered {
do {
let values = try f.resourceValues(forKeys: [.creationDateKey, .contentModificationDateKey])
if let date = values.creationDate{
//let date : Date? = values.contentModificationDate
print(f.lastPathComponent, " ", date)
}
}
catch _{
}
}
}
Swift 3 完整解决方案代码: 基于@ingconti 的回答。此方法 return 提供的 URL 路径中的项目名称列表。
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。基于之前答案的简单扩展:
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 [=10=].resourceValues(forKeys: [key])
let values2 = try .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 { [=10=].lastPathComponent }
}
}
Swift 5.0 使用按修改日期筛选和排序
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 { [=10=].lastPathComponent.hasSuffix(".swift") }
.sorted(by: {
let date0 = try [=10=].promisedItemResourceValues(forKeys:[.contentModificationDateKey]).contentModificationDate!
let date1 = try .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)
}