Swift 2 iOS - 获取按创建日期排序的文件列表 - 更简洁的解决方案?

时间:2015-10-09 07:21:16

标签: ios swift nsfilemanager

在我的代码中,我正在返回一个[String]?,其中包含lastPathComponent中存储的文件名/Documents/ - 按上次修改日期排序。

我相信我可能正在使用太多步骤,我在这里寻求建议如何减少代码。

为了达到目前所需的结果 - 我创建了两个中间词典:var attributesDictionary: [String : AnyObject]?var urlDictionary = [NSURL:NSDate]()。循环使用最初的[NSURL]我正在使用两个步骤 - .resourceValuesForKeys初始化attributesDictionary。然后我填充urlDictionary,使其包含网址和密钥NSURLContentModificationDateKey的值。

我确信应该有一种方法可以在不创建urlDictionaryattributesDictionary且无需循环的情况下实现此结果。也许直接来自urlArray。这是我目前的代码:

编辑:do{}不需要Arthur Gevorkyan在第一条评论中指出。

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{$0 != nil}.sort{$0.1.compare($1.1) == NSComparisonResult.OrderedDescending }.map{$0.0}.map{$0.lastPathComponent!}
    } else {
        return nil
    }
}

7 个答案:

答案 0 :(得分:20)

可能的解决方案:

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
}

首先将URL数组映射到(lastPathComponent, lastModificationDate)元组的数组,然后根据 最后修改日期,最后提取路径名。

使用可以避免attributesDictionary getResourceValue(_ : forKey)仅检索上次修改日期。

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
}

答案 1 :(得分:5)

完整解决方案的Swift 3代码: 根据@ ingconti的回答。此方法返回提供的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
}

答案 2 :(得分:3)

return urlDictionary.filter{$0 != nil}.sort{$0.1.compare($1.1) == NSComparisonResult.OrderedDescending }.map{$0.0}.map{$0.lastPathComponent!}

绝对是一个过度的代码行:) 您可以使用另一种NSFileManager方法跳过几个过滤器/映射步骤:

func contentsOfDirectoryAtPath(_ path: String) throws -> [String] 

func attributesOfItemAtPath(_ path: String) throws -> [String : AnyObject].

最后,你最终得到的东西与你已经完成的东西相当。我认为你的代码有点复杂,但方法非常好。

答案 3 :(得分:1)

Swift 5.0使用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)
}

答案 4 :(得分:0)

Swift 3,iOS 10

// 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)")
      }

答案 5 :(得分:0)

Swift 3.0 Sierra 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 _{

        }
    }


}

答案 6 :(得分:0)

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

}

相关问题