JSON 作為目前最流行的數據傳輸格式, 相信每個程序員都跟它打過交道吧。使用 Go 語言時,也不可避免的要操作 JSON 數據,令人驚喜的是,Go 內置了序列化和反序列化 JSON 的功能,今天就來總結一下。
序列化是將結構對象轉為 JSON 字符串,反序列化是將 JSON 字符串轉為結構對象,它們分別對應 encoding/json 包下面的兩個方法:
// 序列化 接收interface{}參數 返回字節切片
func Marshal(v interface{}) ([]byte, error) { }
// 反序列化 接收字節切片和interface{}參數 將結果反映在interface{}結構上
func Unmarshal(data []byte, v interface{}) error { }
marshal
這個單詞的含義是 整理、編排、排列
,對應的操作是將結構對象編排成 JSON 字符串,反之,unmarshal
是它的逆操作。
我們通過一個例子來演示這兩個方法。假如我們有如下 data.json 文件:
{
"group": "programmer",
"persons": [
{
"name": "Jack",
"age": 25
},
{
"name": "Lily",
"age": 20
}
]
}
接下來,我們要讀取這個文件,將 JSON 內容轉為結構對象,然后更改對象數據:
// 讀取JSON文件 將內容轉為結構對象 然后更改數據
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
)
type (
person struct {
Name string `json:"name"`
Age int `json:"age"`
}
result struct {
Group string `json:"group"`
Persons []person `json:"persons"`
}
)
func main() {
var data result
// 讀取JSON文件內容 返回字節切片
bytes, _ := ioutil.ReadFile("data.json")
fmt.Println("*** data.json content: ***")
// 打印時需要轉為字符串
fmt.Println(string(bytes))
// 將字節切片映射到指定結構上
json.Unmarshal(bytes, &data)
fmt.Println("*** unmarshal result: ***")
// 打印對象結構
fmt.Println(data)
// 更改數據
data.Group = "engineer"
// 將更改后的結構對象序列化成JSON格式
newBytes, _ := json.Marshal(&data)
fmt.Println("*** update content: ***")
// 打印JSON結果
fmt.Println(string(newBytes))
}
上面代碼中,結構體字段的后面都有一串說明性信息,它們被稱為標簽(Tag),用於將結構體和 JSON 數據映射起來,如果不指定,系統會嘗試以大小寫無關的方式去匹配,但為了便於閱讀和避免不必要的匹配過程,我們這里手動指定了具體的字段。
我們運行該程序,控制台會打印如下信息:
{
"group": "programmer",
"persons": [
{
"name": "Jack",
"age": 25
},
{
"name": "Lily",
"age": 20
}
]
}
*** unmarshal result: ***
{programmer [{Jack 25} {Lily 20}]}
*** update content: ***
{"group":"engineer","persons":[{"name":"Jack","age":25},{"name":"Lily","age":20}]}
最后的 JSON 數據還可以在格式化一下,我們可以利用下面這個方法:
// 帶格式化的反序列化方法
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { }
相比 Marshal() 方法,MarshalIndent() 多了兩個參數,分別是前綴和縮進,都是字符串類型。前綴一般不怎么常用,縮進可指定若干個空格,下面我們來改造一下:
// 將更改后的結構對象序列化成JSON格式
newBytes, _ := json.MarshalIndent(&data, "", " ")
fmt.Println("*** indent content: ***")
// 打印JSON結果
fmt.Println(string(newBytes))
再次運行程序,打印結果如下:
*** indent content: ***
{
"group": "engineer",
"persons": [
{
"name": "Jack",
"age": 25
},
{
"name": "Lily",
"age": 20
}
]
}
最后,如果希望將結果寫回到配置文件中的話,可以添加下面這一行代碼:
ioutil.WriteFile("data.json", newBytes, os.ModeAppend)
WriteFile() 方法需要三個參數:文件名、字節切片數據、指定的文件操作權限。如果文件存在,這個方法先會清空文件內容,然后再寫入新數據,如果文件不存在,則根據指定的第三個參數,去先創建指定的文件。
執行完上面這行代碼,再去查看之前的 data.json 文件,就會發現,配置內容已經更新了。