Swift 5 (Xcode 11 Betas 5 & 6) - 如何写入 JSON 文件?
Swift 5 (Xcode 11 Betas 5 & 6) - How to write to a JSON file?
这个问题多年来被问过很多次,但在 Swift 5 中再次 发生了变化,特别是在最后两个测试版中。
读取一个JSON文件似乎很简单:
func readJSONFileData(_ fileName: String) -> Array<Dictionary<String, Any>> {
var resultArr: Array<Dictionary<String, Any>> = []
if let url = Bundle.main.url(forResource: "file", withExtension: "json") {
if let data = try? Data(contentsOf: url) {
print("Data raw: ", data)
if let json = try? (JSONSerialization.jsonObject(with: data, options: []) as! NSArray) {
print("JSON: ", json)
if let arr = json as? Array<Any> {
print("Array: ", arr)
resultArr = arr.map { [=13=] as! Dictionary<String, Any> }
}
}
}
}
return resultArr
}
但是写起来非常困难,之前在这个网站上找到的所有方法在 Swift 5 on Xcode 11 beta 5 和 6 中都失败了。
如何将数据写入 Swift 5 中的 JSON 文件?
我尝试了这些方法:
- read/write local json file swift 4
除了弃用警告之外没有任何错误,当我修复这些错误时,它根本不起作用。
回答问题:
Let's just say I have some JSON data - how would I write it to
file.json? It's in my project directory - is this writable? And if
not, how would I make it writable?
假设 "some JSON" 表示字典数组 [<String, String>]
,这里有一个简单的例子来说明如何做到这一点:
假设我们有以下数组,我们需要将其作为 JSON 写入文件:
let array = [["Greeting":"Hello", "id": "101", "fruit": "banana"],
["Greeting":"Hola", "id": "102", "fruit": "tomato"],
["Greeting":"Salam", "id": "103", "fruit": "Grape"]]
首先要做的是将其转换为 JSON(作为 Data
实例)。有多个选项可以做到这一点,让我们使用 JSONSerialization
一个:
do {
let data = try JSONSerialization.data(withJSONObject: array, options: [])
if let dataString = String(data: data, encoding: .utf8) {
print(dataString)
}
} catch {
print(error)
}
此时,您应该在控制台上看到:
[{"Greeting":"Hello","fruit":"banana","id":"101"},{"fruit":"tomato","Greeting":"Hola","id":"102"},{"fruit":"Grape","Greeting":"Salam","id":"103"}]
这是我们格式化为有效的数据 JSON。
接下来,我们需要将其写入文件中。为此,我们将 FileManager
用作:
do {
let data = try JSONSerialization.data(withJSONObject: array, options: [])
if let documentDirectoryUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
let fileUrl = documentDirectoryUrl.appendingPathComponent("MyFile.json")
try data.write(to: fileUrl)
}
} catch {
print(error)
}
注意文件应该存在于documents目录下;在上面的例子中,它的名字应该是 "MyFile.json".
让我们暂时假设您有一些随机集合(数组或字典或它们的一些嵌套组合):
let dictionary: [String: Any] = ["bar": "qux", "baz": 42]
然后你可以将它保存为 JSON 在“应用程序支持”目录中,如下所示:
do {
let fileURL = try FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent("example.json")
try JSONSerialization.data(withJSONObject: dictionary)
.write(to: fileURL)
} catch {
print(error)
}
关于我们现在使用“Application Support”目录而不是“Documents”文件夹的基本原理,请参阅 iOS Storage Best Practices video or refer to the File System Programming Guide。但是,无论如何,我们使用这些文件夹,而不是应用程序的“bundle”文件夹,它是只读的。
并阅读 JSON 文件:
do {
let fileURL = try FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
.appendingPathComponent("example.json")
let data = try Data(contentsOf: fileURL)
let dictionary = try JSONSerialization.jsonObject(with: data)
print(dictionary)
} catch {
print(error)
}
话虽如此,我们通常更喜欢使用强类型的自定义类型,而不是随机字典,因为后者的负担落在程序员身上,以确保键名中没有拼写错误。无论如何,我们让这些自定义 struct
或 class
类型符合 Codable
:
struct Foo: Codable {
let bar: String
let baz: Int
}
然后我们将使用 JSONEncoder
而不是旧的 JSONSerialization
:
let foo = Foo(bar: "qux", baz: 42)
do {
let fileURL = try FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent("example.json")
try JSONEncoder().encode(foo)
.write(to: fileURL)
} catch {
print(error)
}
并阅读 JSON 文件:
do {
let fileURL = try FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
.appendingPathComponent("example.json")
let data = try Data(contentsOf: fileURL)
let foo = try JSONDecoder().decode(Foo.self, from: data)
print(foo)
} catch {
print(error)
}
有关从自定义类型准备 JSON 的详细信息,请参阅 Encoding and Decoding Custom Types article or the Using JSON with Custom Types 示例代码。
万一有人在使用自定义对象(就像我一样)并且想要更多 'all around' 泛型函数
将文件保存到管理器
func saveJSON<T: Codable>(named: String, object: T) {
do {
let fileURL = try FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent(named)
let encoder = try JSONEncoder().encode(object)
try encoder.write(to: fileURL)
} catch {
print("JSONSave error of \(error)")
}
}
从管理器读取文件
func readJSON<T: Codable>(named: String, _ object: T.Type) -> T? {
do {
let fileURL = try FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent(named)
let data = try Data(contentsOf: fileURL)
let object = try JSONDecoder().decode(T.self, from: data)
return object
} catch {
return nil
}
}
这个问题多年来被问过很多次,但在 Swift 5 中再次 发生了变化,特别是在最后两个测试版中。
读取一个JSON文件似乎很简单:
func readJSONFileData(_ fileName: String) -> Array<Dictionary<String, Any>> {
var resultArr: Array<Dictionary<String, Any>> = []
if let url = Bundle.main.url(forResource: "file", withExtension: "json") {
if let data = try? Data(contentsOf: url) {
print("Data raw: ", data)
if let json = try? (JSONSerialization.jsonObject(with: data, options: []) as! NSArray) {
print("JSON: ", json)
if let arr = json as? Array<Any> {
print("Array: ", arr)
resultArr = arr.map { [=13=] as! Dictionary<String, Any> }
}
}
}
}
return resultArr
}
但是写起来非常困难,之前在这个网站上找到的所有方法在 Swift 5 on Xcode 11 beta 5 和 6 中都失败了。
如何将数据写入 Swift 5 中的 JSON 文件?
我尝试了这些方法:
- read/write local json file swift 4
除了弃用警告之外没有任何错误,当我修复这些错误时,它根本不起作用。
回答问题:
Let's just say I have some JSON data - how would I write it to file.json? It's in my project directory - is this writable? And if not, how would I make it writable?
假设 "some JSON" 表示字典数组 [<String, String>]
,这里有一个简单的例子来说明如何做到这一点:
假设我们有以下数组,我们需要将其作为 JSON 写入文件:
let array = [["Greeting":"Hello", "id": "101", "fruit": "banana"],
["Greeting":"Hola", "id": "102", "fruit": "tomato"],
["Greeting":"Salam", "id": "103", "fruit": "Grape"]]
首先要做的是将其转换为 JSON(作为 Data
实例)。有多个选项可以做到这一点,让我们使用 JSONSerialization
一个:
do {
let data = try JSONSerialization.data(withJSONObject: array, options: [])
if let dataString = String(data: data, encoding: .utf8) {
print(dataString)
}
} catch {
print(error)
}
此时,您应该在控制台上看到:
[{"Greeting":"Hello","fruit":"banana","id":"101"},{"fruit":"tomato","Greeting":"Hola","id":"102"},{"fruit":"Grape","Greeting":"Salam","id":"103"}]
这是我们格式化为有效的数据 JSON。
接下来,我们需要将其写入文件中。为此,我们将 FileManager
用作:
do {
let data = try JSONSerialization.data(withJSONObject: array, options: [])
if let documentDirectoryUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
let fileUrl = documentDirectoryUrl.appendingPathComponent("MyFile.json")
try data.write(to: fileUrl)
}
} catch {
print(error)
}
注意文件应该存在于documents目录下;在上面的例子中,它的名字应该是 "MyFile.json".
让我们暂时假设您有一些随机集合(数组或字典或它们的一些嵌套组合):
let dictionary: [String: Any] = ["bar": "qux", "baz": 42]
然后你可以将它保存为 JSON 在“应用程序支持”目录中,如下所示:
do {
let fileURL = try FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent("example.json")
try JSONSerialization.data(withJSONObject: dictionary)
.write(to: fileURL)
} catch {
print(error)
}
关于我们现在使用“Application Support”目录而不是“Documents”文件夹的基本原理,请参阅 iOS Storage Best Practices video or refer to the File System Programming Guide。但是,无论如何,我们使用这些文件夹,而不是应用程序的“bundle”文件夹,它是只读的。
并阅读 JSON 文件:
do {
let fileURL = try FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
.appendingPathComponent("example.json")
let data = try Data(contentsOf: fileURL)
let dictionary = try JSONSerialization.jsonObject(with: data)
print(dictionary)
} catch {
print(error)
}
话虽如此,我们通常更喜欢使用强类型的自定义类型,而不是随机字典,因为后者的负担落在程序员身上,以确保键名中没有拼写错误。无论如何,我们让这些自定义 struct
或 class
类型符合 Codable
:
struct Foo: Codable {
let bar: String
let baz: Int
}
然后我们将使用 JSONEncoder
而不是旧的 JSONSerialization
:
let foo = Foo(bar: "qux", baz: 42)
do {
let fileURL = try FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent("example.json")
try JSONEncoder().encode(foo)
.write(to: fileURL)
} catch {
print(error)
}
并阅读 JSON 文件:
do {
let fileURL = try FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
.appendingPathComponent("example.json")
let data = try Data(contentsOf: fileURL)
let foo = try JSONDecoder().decode(Foo.self, from: data)
print(foo)
} catch {
print(error)
}
有关从自定义类型准备 JSON 的详细信息,请参阅 Encoding and Decoding Custom Types article or the Using JSON with Custom Types 示例代码。
万一有人在使用自定义对象(就像我一样)并且想要更多 'all around' 泛型函数
将文件保存到管理器
func saveJSON<T: Codable>(named: String, object: T) {
do {
let fileURL = try FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent(named)
let encoder = try JSONEncoder().encode(object)
try encoder.write(to: fileURL)
} catch {
print("JSONSave error of \(error)")
}
}
从管理器读取文件
func readJSON<T: Codable>(named: String, _ object: T.Type) -> T? {
do {
let fileURL = try FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent(named)
let data = try Data(contentsOf: fileURL)
let object = try JSONDecoder().decode(T.self, from: data)
return object
} catch {
return nil
}
}