go json数据处理详解

1. 介绍

JSON 是一种轻量级的数据交换格式,常用作前后端数据交换,Go 在 encoding/json
包中提供了对 JSON 的支持。

2. 用法

2.1 struct 序列化成

把 Go struct 序列化成 JSON 对象,Go 提供了 Marshal
方法,正如其含义所示表示编排序列化,函数签名如下:

func Marshal(v interface{}) ([]byte, error)

第一种写法

package main
import (
    "encoding/json"
    "fmt"
)
type Message struct {
    Name string
    Body string
    Time int64
}

func main() {
   m := Message{"Liming", "Hello", 1294706395881547}
   b, err := json.Marshal(m) 
   if err != nil {
     fmt.Println(err)
   }
   fmt.Println(string(b))
}
$ go run json1.go
{"Name":"Liming","Body":"Hello","Time":1294706395881547}

第二种写法

package main
import (
    "encoding/json"
    "fmt"
)

type Product struct {
    Name      string
    ProductID int64
    Number    int
    Price     float64
    IsOnSale  bool
}

func main() {
    p := &Product{}
    p.Name = "apple 8P"
    p.IsOnSale = true
    p.Number = 1000
    p.Price = 4499.00
    p.ProductID = 1
    data, _ := json.Marshal(p)
    fmt.Println(string(data))
}
$ go run json2.go
{"Name":"apple 8P","ProductID":1,"Number":1000,"Price":4499,"IsOnSale":true}

在 Go 中并不是所有的类型都能进行序列化:

  • JSON object key 只支持 string
  • Channel、complex、function 等 type 无法进行序列化
  • 数据中如果存在循环引用,则不能进行序列化,因为序列化时会进行递归
  • Pointer 序列化之后是其指向的值或者是 nil

还需要注意的是:只有 struct 中支持导出的 field 才能被 JSON package 序列化,即首字母大写的 field。

2.2 Struct Tag

Struct tag 可以决定 Marshal 和 Unmarshal 函数如何序列化和反序列化数据

package main
import (
    "encoding/json"
    "fmt"
)

type Product struct {
    Name      string  `json:"name"`
    ProductID int64   `json:"-"` // 表示不进行序列化
    Number    int     `json:"number"`
    Price     float64 `json:"price"`
    IsOnSale  bool    `json:"is_on_sale,string"`
}
func main() {
    p := &Product{}
    p.Name = "apple 8P"
    p.IsOnSale = true
    p.Number = 1000
    p.Price = 4499.00
    p.ProductID = 1
    data, _ := json.Marshal(p)
    fmt.Println(string(data))
}
$ go run json4.go
{"name":"apple 8P","number":1000,"price":4499,"is_on_sale":"true"}

omitempty,tag里面加上omitempy,可以在序列化的时候忽略0值或者空值或者false。

package main
import (
    "encoding/json"
    "fmt"
)

type Product struct {
    Name      string  `json:"name"`
    ProductID int64   `json:"product_id,omitempty"` 
    Number    int     `json:"number"`
    Price     float64 `json:"price"`
    IsOnSale  bool    `json:"is_on_sale,omitempty"`
}

func main() {
    p := &Product{}
    p.Name = "apple 8P"
    p.IsOnSale = false
    p.Number = 1000
    p.Price = 4499.00
    p.ProductID = 0
    data, _ := json.Marshal(p)
    fmt.Println(string(data))
}
$ go  run json5.go
{"name":"apple 8P","number":1000,"price":4499}

2.3 struct反序列化

反序列化函数是 Unmarshal ,其函数签名如下:

func Unmarshal(data []byte, v interface{}) error
package main
import (
	"encoding/json"
	"fmt"
)
 
type Change struct {
	Mid     int      //菜单Id
	Actions []string //拥有的权限 "add"  "view"  "delete"  "update"
}
type Change_slice struct {
	ChgArr []Change //一个角色对应的菜单以及权限
}
func main() {
        var str string = `{"ChgArr":[{"Mid":1,"Actions":["view","add"]},{"Mid":2,"Actions":["delete","add","update"]}]}`
	var msgs Change_slice
	err := json.Unmarshal([]byte(str), &msgs)
	if err != nil {
		fmt.Println("Can't decode json message", err)
	} else {
		fmt.Println(msgs.ChgArr[1].Mid)
	}

}
$  go run json3.go
2

2.4 Tag反序列化

带标签(tag)的结构体(struct)

package main

import (
    "encoding/json"
    "fmt"
)

// Product _
type Product struct {
    Name      string  `json:"name"`
    ProductID int64   `json:"product_id,string"`
    Number    int     `json:"number,string"`
    Price     float64 `json:"price,string"`
    IsOnSale  bool    `json:"is_on_sale,string"`
}

func main() {

    var data = `{"name":"apple 8P","product_id":"10","number":"10000","price":"6000","is_on_sale":"true"}`
    p := &Product{}
    err := json.Unmarshal([]byte(data), p)
    if err != nil {
       fmt.Println(err)
    }
    fmt.Println(*p)
}
$ go run json6.go
{apple 8P 10 10000 6000 true}

另外一种反序列化(格式)

var m Product
err := json.Unmarshal(b, &m)

2.5 interface{}反序列化

针对未知类型json

package main

import (
	"encoding/json"
	"fmt"
)

func main() {
	a := `{"name":"chalvern.github.io","full_name":"chalvern/chalvern.github.io","private":false,"owner":{"login":"chalvern","html_url":"https://github.com/chalvern"},"html_url":"https://github.com/chalvern/chalvern.github.io","description":"jingwei.link blog"}`

	var jingweiI interface{}
	err := json.Unmarshal([]byte(a), &jingweiI)
        if err != nil {
           fmt.Println(err)
        }
	fmt.Printf("%#v \n %#v \n", jingweiI)
	// 获取某个 key 的值
	jingweiM, ok := jingweiI.(map[string]interface{})
	if !ok {
		fmt.Println("DO SOMETHING!")
		return
	}
	fmt.Printf("%#v\n", jingweiM["name"])
	//  获取嵌套的内容
	owner, ok := jingweiM["owner"].(map[string]interface{})
	if !ok {
		fmt.Println("DO SOMETHING!")
		return
	}
	fmt.Printf("%#v\n", owner["login"])
}
$ go run json8.go
map[string]interface {}{"description":"jingwei.link blog", "full_name":"chalvern/chalvern.github.io", "html_url":"https://github.com/chalvern/chalvern.github.io", "name":"chalvern.github.io", "owner":map[string]interface {}{"html_url":"https://github.com/chalvern", "login":"chalvern"}, "private":false} 
 %!v(MISSING) 
"chalvern.github.io"
"chalvern"

2.6 编码解码

编码

json.NewEncoder(<Writer>).encode(v)
json.Marshal(&v)

解码

json.NewDecoder(<Reader>).decode(&v)
json.Unmarshal([]byte, &v)

除了 marshal 和 unmarshal 函数,Go 还提供了 Decoder 和 Encoder 对 stream JSON 进行处理,常见 request 中的 Body、文件等。

$ cat post.json 
{
  "name":"apple 8P",
  "product_id":10,
  "number":10000,
  "price":6000,
  "is_on_sale":"true"
}
$ cat json9.go 
package main
import (
 "encoding/json"
 "fmt"
 "io"
 "os"
)

type Product struct {
    Name      string
    ProductID int64
    Number    int
    Price     float64
    IsOnSale  bool
}


func main() {
  jsonFile, err := os.Open("post.json")
  if err != nil {
      fmt.Println("Error opening json file:", err)
      return
  }

  defer jsonFile.Close()
  decoder := json.NewDecoder(jsonFile)
  for {
      var post Product
      err := decoder.Decode(&post)
      if err == io.EOF {
	  break
      }

      if err != nil {
	  fmt.Println("error decoding json:", err)
	  return
      }

      fmt.Println(post)
  }
}
$ go  run json9.go
{apple 8P 0 10000 6000 false}

3. 实战

3.1 编码解码比较

package main

import (
    "encoding/json"
    "fmt"
    "bytes"
    "strings"
)

type Person struct {
    Name string `json:"name"`
    Age int `json:"age"`
}

func main()  {
    // 1. 使用 json.Marshal 编码
    person1 := Person{"张三", 24}
    bytes1, err := json.Marshal(&person1)
    if err == nil {
        // 返回的是字节数组 []byte
        fmt.Println("json.Marshal 编码结果: ", string(bytes1))
    }

    // 2. 使用 json.Unmarshal 解码
    str := `{"name":"李四","age":25}`
    // json.Unmarshal 需要字节数组参数, 需要把字符串转为 []byte 类型
    bytes2 := []byte(str) // 字符串转换为字节数组
    var person2 Person    // 用来接收解码后的结果
    if json.Unmarshal(bytes2, &person2) == nil {
        fmt.Println("json.Unmarshal 解码结果: ", person2.Name, person2.Age)
    }

    // 3. 使用 json.NewEncoder 编码
    person3 := Person{"王五", 30}
    // 编码结果暂存到 buffer
    bytes3 := new(bytes.Buffer)
    _ = json.NewEncoder(bytes3).Encode(person3)
    if err == nil {
        fmt.Print("json.NewEncoder 编码结果: ", string(bytes3.Bytes()))
    }

    // 4. 使用 json.NewDecoder 解码
    str4 := `{"name":"赵六","age":28}`
    var person4 Person
    // 创建一个 string reader 作为参数
    err = json.NewDecoder(strings.NewReader(str4)).Decode(&person4)
    if err == nil {
        fmt.Println("json.NewDecoder 解码结果: ", person4.Name, person4.Age)
    }
}

结果:

json.Marshal 编码结果:  {"name":"张三","age":24}
json.Unmarshal 解码结果:  李四 25
json.NewEncoder 编码结果: {"name":"王五","age":30}
json.NewDecoder 解码结果:  赵六 28

3.2 针对未知类型的json

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`)

    var f interface{}
    json.Unmarshal(b, &f)

    m := f.(map[string]interface{})
    fmt.Println(m["Parents"])  // 读取 json 内容
    fmt.Println(m["a"] == nil) // 判断键是否存在
}
$ go run json11.go
[Gomez Morticia]
true

参考连接:
https://learnku.com/go/t/23565/golang-json-coding-and-decoding-summary
https://jingwei.link/2019/03/15/golang-json-unmarshal-using.html
https://sanyuesha.com/2018/05/07/go-json/

原创文章 223 获赞 57 访问量 12万+

猜你喜欢

转载自blog.csdn.net/xixihahalelehehe/article/details/105890394