日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Go 学习笔记(20)— Go 操作 json 文件(编码生成 json、解码 json 为 map、解码 json 为 struct)

發布時間:2023/11/27 生活经验 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Go 学习笔记(20)— Go 操作 json 文件(编码生成 json、解码 json 为 map、解码 json 为 struct) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. Json 概述

Go 語言對于標準格式的編碼和解碼都有良好的支持,由標準庫中的 encoding/jsonencoding/xmlencoding/asn1 等包提供支持并且這類包都有著相似的 API 接口。

json 類型有數字(十進制或科學記數法)、布爾值( truefalse)、字符串,其中字符串是以 雙引號 包含的 Unicode 字符序列。

基礎類型可以通過 json 的數組和對象類型進行遞歸組合:

  • 一個 JSON 數組是一個有序的值序列,寫在一個方括號中并以逗號分隔;
  • 一個 JSON 數組可以用于編碼 Go 語言的數組和 slice
  • 一個 JSON 對象是一個字符串到值的映射,寫成一系列的 name:value 對形式,用花括號包含并以逗號分隔;
  • JSON 的對象類型可以用于編碼 Go 語言的 map 類型 ( key 類型是字符串)和結構體;

標準庫 encoding/json 解析 JSON 有兩種方式:

  • 根據 JSON 內容格式定義對應的結構體(struct)
  • 使用 map[string]interface{} 加載 JSON 數據。

實際工作中,個人不建議采用根據 JSON 內容格式定義對應的結構體(struct),當 JSON 內容格式過于復雜的時候,對應的結構體(struct)的定義過程會變得復雜,這樣會增加大量的代碼。

因此建議使用 map[string]interface{} 加載 JSON 數據。

2. 代碼示例

package mainimport ("encoding/json""fmt""log"
)// Movie struct
type Movie struct { // 只有導出的結構體成員才會被編碼,所以此處 Movie 用大寫字母表示Title  stringYear   int  `json:"released"`Color  bool `json:"color,omitempty"`Actors []string
}var movies = []Movie{{Title: "中國機長", Year: 2019, Color: true, Actors: []string{"張涵予", "袁泉"}},{Title: "攀登者", Year: 2019, Color: true, Actors: []string{"吳京", "章子怡"}},
}func main() {jsonStr, err := json.MarshalIndent(movies, "", "    ")if err != nil {log.Fatal(err)return}fmt.Printf("%s\n", jsonStr)}

輸出:

  [{"Title": "中國機長","released": 2019,"color": true,"Actors": ["張涵予","袁泉"]},{"Title": "攀登者","released": 2019,"color": true,"Actors": ["吳京","章子怡"]}]

在編碼時,默認使用 Go 語言結構體的成員名字作為 JSON 的對象。只有導出的結構體成員才會被編碼,這也就是我們為什么選擇用大寫字母開頭的成員名稱。

type Movie struct { // 只有導出的結構體成員才會被編碼,所以此處 Movie 用大寫字母表示

其中 Year 名字的成員在編碼后變成了 released ,還有 Color 成員編碼后變成了小寫字母開頭的 color 。這是因為結構體成員 Tag 所導致的。

{"Title": "中國機長","released": 2019,"color": true,"Actors": ["張涵予","袁泉"]}

結構體的成員 Tag 可以是任意的字符串面值,但是通常是一系列用空格分隔的 key:"value" 鍵值對序列;因為值中含有雙引號字符,因此成員 Tag 一般用原生字符串面值的形式書寫。

json 開頭鍵名對應的值用于控制 encoding/json 包的編碼和解碼的行為,并且 encoding/... 下面其它的包也遵循這個約定。

Year   int  `json:"released"`

Color 成員的 Tag 還帶了一個額外的 omitempty 選項,表示當 Go 語言結構體成員為空或零值時不生成該 JSON 對象(這里false為零值)。如果 【攀登者】 是一個黑白電影,就不會輸出 Color 成員。

Color  bool `json:"color,omitempty"`

編碼的逆操作是解碼,對應將 JSON 數據解碼為 Go 語言的數據結構, Go 語言中一般叫 unmarshaling ,通過 json.Unmarshal 函數完成。下面的代碼將 JSON 格式的電影數據解碼為一個結構體 slice ,結構體中只有 Title 成員。

通過定義合適的 Go 語言數據結構,我們可以選擇性地解碼 json 中感興趣的成員。當 Unmarshal 函數調用返回, slice 將被只含有 Title 信息的值填充,其它 JSON 成員將被忽略。

package mainimport ("encoding/json""fmt""log"
)// Movie struct
/*
注意
1. json 編解碼 只能處理結構體成員變量是大寫的字段,小寫的直接忽略
2. 如果在編碼時 想讓json字符串的字段小寫,那么需要再結構體中加Tag如果再解碼時, json有小寫的字段名,那么在定義結構體接收的時候,成員名要大寫,然后也要加Tag*/
type Movie struct { // 只有導出的結構體成員才會被編碼,所以此處 Movie 用大寫字母表示Title  stringYear   int  `json:"released"`Color  bool `json:"color,omitempty"`Actors []string
}var movies = []Movie{{Title: "中國機長", Year: 2019, Color: true, Actors: []string{"張涵予", "袁泉"}},{Title: "攀登者", Year: 2019, Color: true, Actors: []string{"吳京", "章子怡"}},
}func main() {// 編碼將 go 結構體轉換成 json 字符串jsonData, err := json.MarshalIndent(movies, "", " ")if err != nil {log.Fatal(err)return}fmt.Printf("jsonData is %s\n", jsonData)fmt.Println("-----------------")//解碼,將json字符串 轉換成 go數據類型var titles []struct {Title string}if err := json.Unmarshal(jsonData, &titles); err != nil {log.Fatal(err)return}fmt.Printf("%+v\n", titles)var years []struct {Year int `json:"released"`}if err := json.Unmarshal(jsonData, &years); err != nil {log.Fatal(err)return}fmt.Printf("%+v\n", years)var actors []struct {Actors []string}if err := json.Unmarshal(jsonData, &actors); err != nil {log.Fatal(err)return}fmt.Printf("%+v\n", actors)fmt.Println("-----------------")var myMovies []struct {Title  stringYear   int `json:"released"`Actors []string}if err := json.Unmarshal(jsonData, &myMovies); err != nil {log.Fatal(err)return}fmt.Printf("%+v\n", myMovies)
}

輸出結果:

jsonData is [{"Title": "中國機長","released": 2019,"color": true,"Actors": ["張涵予","袁泉"]},{"Title": "攀登者","released": 2019,"color": true,"Actors": ["吳京","章子怡"]}
]
-----------------
[{Title:中國機長} {Title:攀登者}]
[{Year:2019} {Year:2019}]
[{Actors:[張涵予 袁泉]} {Actors:[吳京 章子怡]}]
-----------------
[{Title:中國機長 Year:2019 Actors:[張涵予 袁泉]} {Title:攀登者 Year:2019 Actors:[吳京 章子怡]}]

3. 編碼生成 json

使用 json 包的 MarshalIndent 函數進行編碼。這個函數可以很方便地將 Go 語言的 map 類型的值或者結構類型的值轉換為易讀格式的 JSON 文檔。

序列化( marshal)是指將數據轉換為 JSON字符串的過程。

// 這個示例程序展示如何序列化JSON字符串
package mainimport ("encoding/json""fmt""log"
)func main() {// 創建一個保存鍵值對的映射c := make(map[string]interface{})c["Name"] = "wohu"c["Year"] = "2019"c["Contact"] = map[string]interface{}{"home": "12345678","cell": "110110",}// 將這個映射序列化到JSON字符串data, err := json.MarshalIndent(c, "", "  ")if err != nil {log.Println("ERROR:", err)return}fmt.Println(string(data))
}

輸出:

{"Contact": {"cell": "110110","home": "12345678"},"Name": "wohu","Year": "2019"
}

函數 MarshalIndent 返回一個 byte 切片,用來保存 JSON 字符串和一個 error值。

// MarshalIndent很像Marshal,只是用縮進對輸出進行格式化
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {

MarshalIndent函數里再一次看到使用了空接口類型 interface{}。函數 MarshalIndent 會使用反射來確定如何將 map 類型轉換為 JSON 字符串。

4. 解碼 json 為 map

JSON 數據里邊的元素類型將做如下轉換:

  • JSON 中的布爾值將會轉換為 Go 中的 bool 類型;
  • 數值會被轉換為 Go 中的 float64 類型;
  • 字符串轉換后還是 string 類型;
  • JSON 數組會轉換為 []interface{} 類型;
  • JSON 對象會轉換為 map[string]interface{} 類型;
  • null 值會轉換為 nil

4.1 解碼 json 字符串

可以將 JSON 文檔解碼到一個 map 變量中。

// 這個示例程序展示如何解碼JSON字符串
package mainimport ("encoding/json""fmt""log"
)// JSON 包含要反序列化的樣例字符串var JSON = `{"name": "wohu","year": "2020","contact": {"home": "12345678","cell": "110110"}
}`func main() {// 將JSON字符串反序列化到map變量// 變量c聲明為一個map類型,其鍵是string類型,其值是interface{}類型。// 這意味著這個map類型可以使用任意類型的值作為給定鍵的值。var c map[string]interface{}err := json.Unmarshal([]byte(JSON), &c)if err != nil {log.Println("ERROR:", err)return}fmt.Println("Name:", c["name"])fmt.Println("Year:", c["year"])fmt.Println("Contact")// 因為每個鍵的值的類型都是interface{},所以必須將值轉換為合適的類型,才能處理這個值。// 下面展示了如何將contact鍵的值轉換為另一個鍵是string類型,值是interface{}類型的map類型。fmt.Println("H:", c["contact"].(map[string]interface{})["home"])fmt.Println("C:", c["contact"].(map[string]interface{})["cell"])
}

輸出:

Name: wohu
Year: 2020
Contact
H: 12345678
C: 110110

4.2 解碼 json 文件

demo.json 內容:

{"name": "wohu","year": "2020","contact": {"home": "12345678","cell": "110110"}
}

代碼:

package mainimport ("encoding/json""fmt""io/ioutil"
)func main() {content, _ := ioutil.ReadFile("demo.json")r := make(map[string]interface{})json.Unmarshal([]byte(content), &r)fmt.Println("r['name'] is ", r["name"])
}

5. 解碼 json 為 struct

package mainimport ("encoding/json""fmt""io/ioutil"
)type Contact struct {Home string `json:"home"`Cell string `json:"cell"`
}type Student struct {Name    string  `json:"name"`Year    string  `json:"year"`Contact Contact `json:"contact"`
}// 全局 單例模式
var Gjson *Studentfunc display() {fmt.Println("student.name is ", Gjson.Name)fmt.Println("student.Contact.Home is ", Gjson.Contact.Home)fmt.Println("student.Contact.Cell is ", Gjson.Contact.Cell)
}func main() {content, _ := ioutil.ReadFile("demo.json")var student Studentjson.Unmarshal(content, &student)// 執行以下代碼之后,后面就可以使用全局的 Gjson 來獲取配置文件中的字段Gjson = &studentdisplay()
}

6. 三方庫

除此之外,Go 的第三方包也支持 JSON 數據的解析,我們以 jsoniter 為例。第三包 jsoniter 是 100% 兼容原生庫,但是性能超級好,預先緩存了對應 structdecoder 實例,然后 unsafe.Pointer 省掉了一些 interface{} 的開銷,還有一些文本解析上的優化,并且它的使用方式與標準庫 encoding/json 存在相似。

安裝第三包 jsoniter 命令 :

go get -v github.com/json-iterator/go

示例代碼

package mainimport ("fmt""io/ioutil"jsoniter "github.com/json-iterator/go"
)func main() {content, _ := ioutil.ReadFile("demo.json")r := make(map[string]interface{})json := jsoniter.ConfigCompatibleWithStandardLibraryjson.Unmarshal([]byte(content), &r)fmt.Println("r['name'] is ", r["name"])}
	r := make(map[string]interface{})fmt.Println([]byte(result))// 調用標準庫encoding/json的Unmarshal// 將JSON數據(JSON以字符串形式表示)轉換成[]byte,并將數據加載到對象r的內存地址json.Unmarshal([]byte(result), &r)// r["data"]是讀取JSON最外層的key// 如果嵌套JSON數據,則使用map[string]interface{}讀取下一層的JSON數據// 如讀取key為data里面嵌套的result:r["data"].(map[string]interface{})["result"]// 如果JSON的某個key的數據以數組表示,則使用([]interface{})[index]讀取數組中某個數據。// 如讀取key為result的第四個數據:r["data"].(map[string]interface{})["result"].([]interface{})[3]fmt.Println(r["data"].(map[string]interface{})["result"].([]interface{})[3])

總結

以上是生活随笔為你收集整理的Go 学习笔记(20)— Go 操作 json 文件(编码生成 json、解码 json 为 map、解码 json 为 struct)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。