web-dev-qa-db-ja.com

Swift 2 iOS-作成日でソートされたファイルリストを取得-より簡潔な解決策?

動作する私のコードでは、_[String]?_に格納されているファイル(lastPathComponent)の名前を含む_/Documents/_を返します-最後に変更された日付順に並べられています。

私はおそらくあまりにも多くのステップを使用していると思います。コードを減らす方法についてここでアドバイスを探しています。

現在必要な結果を達成するために、私は2つの中間辞書_var attributesDictionary: [String : AnyObject]?_とvar urlDictionary = [NSURL:NSDate]()を作成しています。最初の_[NSURL]_をループする2つのステップを使用しています-_.resourceValuesForKeys_はattributesDictionaryを初期化します。次に、urlDictionaryにデータを入力して、キーNSURLContentModificationDateKeyのURLと値が含まれるようにします。

urlDictionaryattributesDictionaryを作成せずに、ループを必要とせずに、この結果を達成する方法があるはずだと私はかなり確信しています。おそらくurlArrayから直接。これが私の現在のコードです:

編集:最初のコメントでArthur Gevorkyanが指摘したように、_do{}_ sは必要ありませんでした。

_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
    }
}
_
16
simons

考えられる解決策:

_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
}
_
23
Martin R

完全なソリューションを備えた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
}
5
mriaz0011
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

Swift5.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 }
}

}

1
Jovan Stankovic

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 _{

        }
    }


}
0
ingconti

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)")
      }
0
Mihail Salari