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.

我相当肯定应该有一种方法可以在不创建 urlDictionaryattributesDictionary 并且不需要循环的情况下实现这个结果。也许直接来自 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)
}