Swift3 如何将字典写入文件?

Swift3 如何将字典写入文件?,swift3,nsfilemanager,nskeyedarchiver,swift-dictionary,Swift3,Nsfilemanager,Nskeyedarchiver,Swift Dictionary,我有一个FileHelper类,我在其中实现了3个方法,它们的工作是将字典内容写入文件。这些方法是: func storeDictionary(_ dictionary: Dictionary<String, String>, inFile fileName: String, atDirectory directory: String) -> Bool { let ext = "txt" let filePath = createFile(fileName, w

我有一个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
}
它起作用了

NSKeyedArchiver.archiveRootObject(u∶toFile:)
method有什么问题


为什么
FileManager.default.createFile(atPath:.filePath?.absoluteString)!,内容:nil,属性:nil)
始终返回false?

首先
文件路径?.absoluteString
返回整个–偶数转义百分比–字符串,包括
文件://
方案,该方法需要一个没有方案的路径(
文件路径?.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
}

这里有一个swift 5扩展,它可以保存
键和
值都是
可编码的词典

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

嗯,我明白了。但是您所说的文件路径是什么意思?.path-命名有点混乱;-),我不知道你的
文件路径实际上是
文件URL
,一个
(NS)URL
实例。
路径
意味着是
(NS)字符串
。哦,我的错。愚蠢的是,如果要忽略相应的(外部)参数标签,您必须通过
。但是,Swift 3约定传递所有参数标签。有时,出于Objective-C兼容性的原因,他们会被忽略。很高兴知道(
\uu
)基本上是用来让来自Objective-C背景的人感觉自己像Objective-C约定。对吗?
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