【问题标题】:How to write Dictionary to a file?如何将字典写入文件?
【发布时间】:2017-08-05 21:38:37
【问题描述】:

我有一个 FileHelper 类,我在其中实现了 3 个方法,它们的工作是将字典内容写入文件。这些方法是:

func storeDictionary(_ dictionary: Dictionary<String, String>, inFile fileName: String, atDirectory directory: String) -> Bool {
    let ext = "txt"
    let filePath = createFile(fileName, withExtension: ext, atDirectory: directory)
    /**** //If I use this method, file is created and dictionary is saved
    guard (dictionary as NSDictionary).write(to: filePath!, atomically: true) else {
        return false
    }
    */
    guard NSKeyedArchiver.archiveRootObject(dictionary, toFile: (filePath?.absoluteString)!) else {
        return false
    }
    return true
}
func createFile(_ file: String, withExtension ext: String, atDirectory directory: String) -> URL? {
    let directoryPath = createDirectory(directory)
    let filePath = directoryPath?.appendingPathComponent(file).appendingPathExtension(ext)

    if !FileManager.default.fileExists(atPath: (filePath?.absoluteString)!) {
        let success = FileManager.default.createFile(atPath: (filePath?.absoluteString)!, contents: nil, attributes: nil)
        print("\(success)") //** here is the issue I investigated. Always prints false.
    }

    return filePath
}
func createDirectory(_ directory: String) -> URL? {
    let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
    let directoryPath = documentsDirectory.appendingPathComponent(directory)

    do {
        try FileManager.default.createDirectory(at: directoryPath, withIntermediateDirectories: true, attributes: nil)
    } catch let error as NSError {
        fatalError("Error creating directory: \(error.localizedDescription)")
    }
    return directoryPath
}

当我调用FileHelper().storeDictionary(aValidDictionary, inFile: "abc", atDirectory: "XYZ") 编写字典时,此过程失败。但是如果我使用

guard (dictionary as NSDictionary).write(to: filePath!, atomically: true) else {
    return false
}

它有效。

NSKeyedArchiver.archiveRootObject(_:toFile:) 方法有什么问题??

为什么FileManager.default.createFile(atPath: (filePath?.absoluteString)!, contents: nil, attributes: nil)总是返回false?

【问题讨论】:

    标签: swift3 nsfilemanager nskeyedarchiver swift-dictionary


    【解决方案1】:

    首先filePath?.absoluteString 返回包括file:// 方案在内的整个字符串(甚至转义百分比),并且该方法需要一个没有该方案的路径(filePath?.path - 命名有点混乱;-))。

    我建议将[String:String] 字典保存为属性列表文件。无需显式创建文件。

    我在 Swift-3-way 中稍微更改了方法的签名。此外,无需使用任何可选类型。

    func store(dictionary: Dictionary<String, String>, in fileName: String, at directory: String) -> Bool {
        let fileExtension = "plist"
        let directoryURL = create(directory:directory)
        do {
            let data = try PropertyListSerialization.data(fromPropertyList: dictionary, format: .xml, options: 0)
            try data.write(to: directoryURL.appendingPathComponent(fileName).appendingPathExtension(fileExtension))
            return true
        }  catch {
            print(error)
            return false
        }
    }
    
    func create(directory: String) -> URL {
        let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
        let directoryURL = documentsDirectory.appendingPathComponent(directory)
    
        do {
            try FileManager.default.createDirectory(at: directoryURL, withIntermediateDirectories: true, attributes: nil)
        } catch let error as NSError {
            fatalError("Error creating directory: \(error.localizedDescription)")
        }
        return directoryURL
    }
    

    PS:您可以让 store 方法可以抛出并在调用方法中处理错误,而不是返回 Bool

    func store(dictionary: Dictionary<String, String>, in fileName: String, at directory: String) throws {
        let fileExtension = "plist"
        let directoryURL = create(directory:directory)
    
        let data = try PropertyListSerialization.data(fromPropertyList: dictionary, format: .xml, options: 0)
        try data.write(to: directoryURL.appendingPathComponent(fileName).appendingPathExtension(fileExtension))
    }
    

    【讨论】:

    • 嗯,我明白了。但是您所说的 filePath?.path 是什么意思 - 命名有点混乱 ;-),我没明白
    • 您的filePath 实际上是fileURL,一个(NS)URL 实例。 path 意味着是 (NS)String
    • 哦,我的错。傻?。我想知道的另一件事是从方法签名中删除_ Swift-3 方式?那么什么时候使用_s?
    • 如果你想忽略相应的(外部)参数标签,你必须传递_。然而,Swift 3 约定是传递所有参数标签。有时出于 Objective-C 兼容性的原因,它们会被忽略。
    • 很高兴知道它 (_) 主要用于那些来自 Objective-C 背景的人,让自己感觉像 Objective-C 约定。对吗?
    【解决方案2】:

    这是一个 swift 5 扩展,它应该保存 KeyValueCodable 的任何字典

    extension Dictionary where Key: Codable, Value: Codable {
        static func load(fromFileName fileName: String, using fileManager: FileManager = .default) -> [Key: Value]? {
            let fileURL = Self.getDocumentsURL(on: .cachesDirectory, withName: fileName, using: fileManager)
            guard let data = fileManager.contents(atPath: fileURL.path) else { return nil }
            do {
                return try JSONDecoder().decode([Key: Value].self, from: data)
            } catch(let error) {
                print(error)
                return nil
            }
        }
    
        func saveToDisk(on directory: FileManager.SearchPathDirectory,
                        withName name: String,
                        using fileManager: FileManager = .default) throws {
    
            let fileURL = Self.getDocumentsURL(on: .cachesDirectory, withName: name, using: fileManager)
            let data = try JSONEncoder().encode(self)
            try data.write(to: fileURL)
        }
    
        private static func getDocumentsURL(on directory: FileManager.SearchPathDirectory,
                                     withName name: String,
                                     using fileManager: FileManager) -> URL {
    
            let folderURLs = fileManager.urls(for: .cachesDirectory, in: .userDomainMask)
            let fileURL = folderURLs[0].appendingPathComponent(name)
            return fileURL
        }
    }
    

    用法:

    let myDict = [MyKey: MyValue].load(from: diskDirectory, andFileName: diskFileName) // load
    try myDict.saveToDisk(on: diskDirectory, withName: diskFileName) // save
    

    【讨论】:

      猜你喜欢
      • 2021-07-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-03
      相关资源
      最近更新 更多