Golang_21: Go语言 JSON 编码 和 解码

原文链接:https://xiets.blog.csdn.net/article/details/130866967

版权声明:原创文章禁止转载

专栏目录:Golang 专栏(总目录)

Go 内置的 encoding/json 包实现了 RFC 7159 中定义的 JSON 的编码和解码。JSON 和 Go 数据类型之间的映射在 json.Marshal()json.Unmarshal() 函数的文档中进行了描述。有关 JSON 和 Go 的详细介绍,可以参考:https://go.dev/blog/json

1. JSON 的简单 编码 和 解码

encoding/json 包中 JSON 编码和解码相关函数:

// 编码: Go -> JSON
// 把任意 Go 的数据类型编码为 JSON, 返回 []byte形式的JSON 和 错误
func Marshal(v any) ([]byte, error)

// 解码: JSON -> GO
// 把 []byte形式的JSON 解码保存到 Go数量类型v
func Unmarshal(data []byte, v any) error


// 格式/缩进JSON: 把 JSON(src) 使用 indent 作为缩进字符串, 并添加 prefix 前缀, 把结果保存到 dst
func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error

// 编码后格式化/缩进 JSON, 使用 indent 作为缩进字符串, 并添加 prefix 前缀
func MarshalIndent(v any, prefix, indent string) ([]byte, error)


// 压缩JSON: 把 JSON(src) 中可以省略的 空格、TAB、换行符 删掉, 把结果保存到 dst
func Compact(dst *bytes.Buffer, src []byte) error

// HTML字符转换: 把 JSON(src) 中 <、>、&、U+2028 和 U+2029 字符
// 更改为 \u003c、\u003e、\u0026、\u2028、\u2029, 以便 JSON 安全地嵌入 HTML <script> 标签
func HTMLEscape(dst *bytes.Buffer, src []byte)


// 判断 data 是否是 有效的 JSON 格式
func Valid(data []byte) bool

使用 json.Marshal(v any) ([]byte, error)json.Unmarshal(data []byte, v any) error 函数对 JSON 进行直接 编码 和 解码。

代码示例:

package main

import (
    "encoding/json"
    "fmt"
)

type Person struct {
    Name   string
    Age    int
    Salary float64
    IsMale bool
}

func main() {
    p1 := Person{"Hello 世界", 25, 8888.88, true}

    // 把 结构体对象(变量或指针均可) 编码为 JSON, 返回 []byte 和 错误
    jsonBytes, _ := json.Marshal(p1)
    fmt.Println(string(jsonBytes)) // {"Name":"Hello 世界","Age":25,"Salary":8888.88,"IsMale":true}

    // 把 JSON 解码到 指针p2 指向的变量中 (必须传指针, 不能传普通变量)
    p2 := &Person{}
    _ = json.Unmarshal(jsonBytes, p2)
    fmt.Printf("%#v\n", *p2) // main.Person{Name:"Hello 世界", Age:25, Salary:8888.88, IsMale:true}

    // 编码JSON, 并格式化, 加上 "=" 前缀, 使用 "---" 缩进
    jsonBytes, _ = json.MarshalIndent(p1, "=", "---")
    fmt.Println(string(jsonBytes))
    // {
    // =---"Name": "Hello 世界",
    // =---"Age": 25,
    // =---"Salary": 8888.88,
    // =---"IsMale": true
    // =}
}

上面示例中,JSON 的字段名默认保持与结构体字段名一致,而 Go 的可导出字段以大写字母开头。可以在 Go 结构体字段后面添加对转换为 JSON 字段时重命名的字符串标签(tag),Go 将通过反射的形式读取标签值完成对字段的读写:

package main

import (
    "encoding/json"
    "fmt"
)

type Person struct {
    Name   string  `json:"name"`
    Age    int     `json:"age"`
    Salary float64 `json:"salary"`
    IsMale bool    `json:"is_male"`
}

func main() {
    p1 := Person{"Hello 世界", 25, 8888.88, true}

    // 把 结构体对象(变量或指针均可) 编码为 JSON, 返回 []byte 和 错误
    jsonBytes, _ := json.Marshal(p1)
    fmt.Println(string(jsonBytes)) // {"name":"Hello 世界","age":25,"salary":8888.88,"is_male":true}

    // 把 JSON 解码到 指针p2 指向的变量中 (必须传指针, 不能传普通变量)
    p2 := &Person{}
    _ = json.Unmarshal(jsonBytes, p2)
    fmt.Printf("%#v\n", *p2) // main.Person{Name:"Hello 世界", Age:25, Salary:8888.88, IsMale:true}
}

2. 解码任意数据(Go 通用的 JSON 模型)

json 包默认使用 map[string]interface{}[]interface{} 来存储 JSON 的 对象数组。在不知道 JSON 数据具体结构的情况下,可以将任何 JSON 解码为一个 interface{} 值,然后通过类型断言来获取具体指。

JSON 数据类型默认对应的 Go 类型为:

JSON 类型Go 类型
stringstring
numberfloat64
booleanbool
nullnil
objectmap[string]interface{}
array[]interface{}

代码示例:

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    // JSON
    jsonString := `{"name":"Hello 世界","age":25,"salary":8888.88,"is_male":true,"parents":["Hello","World"]}`

    // 解码 JSON, 把结果赋值给 接口j
    var j interface{}
    _ = json.Unmarshal([]byte(jsonString), &j)
    fmt.Printf("%#v\n", j) // map[age:25 is_male:true name:Hello 世界 parents:[Hello World] salary:8888.88]

    /* 解码后 p 的结构:
    j = map[string]interface{}{
        "name":    "Hello 世界",
        "age":     25,
        "salary":  8888.88,
        "is_male": true,
        "parents": []interface{}{
            "Hello",
            "World",
        },
    }
    */

    // 通过断言获取指定字段的值
    if jsonObj, ok := j.(map[string]interface{}); ok {
        if age, ok := jsonObj["age"]; ok {
            if ageFloat, ok := age.(float64); ok {
                fmt.Printf("age = %f\n", ageFloat)
            }
        }
    }

    // 使用 map[string]interface{} 和 []interface{} 手动构造任何 JSON 结构, 然后编码为 JSON
    m := map[string]interface{}{
        "name":    "Hello 世界",
        "age":     25,
        "salary":  8888.88,
        "is_male": true,
        "parents": []interface{}{
            "Hello",
            "World",
        },
    }
    jm, _ := json.Marshal(m)
    fmt.Println(string(jm))
    // {"age":25,"is_male":true,"name":"Hello 世界","parents":["Hello","World"],"salary":8888.88}
}

3. 流式 编码器 和 解码器

json 包提供了 json.Decoderjson.Encoder 类型来支持流式读取和写入 JSON 数据的常见操作。

json 包中创建 DecoderEncoder 的函数:

// 创建 JSON 解码器, 从 r 中读取 JSON数据
func NewDecoder(r io.Reader) *Decoder

// 创建 JSON 编码器, 把编码结果写到 w
func NewEncoder(w io.Writer) *Encoder

代码示例:

package main

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

func main() {
    jsonString := `{"name":"Hello 世界","age":25,"salary":8888.88,"is_male":true}`

    reader := strings.NewReader(jsonString)
    var j interface{}

    // 创建解码器, 从 reader 中读取 JSON 数据
    decoder := json.NewDecoder(reader)
    // 把解码结果保存到 j
    _ = decoder.Decode(&j)

    fmt.Printf("%#v\n", j)
    // map[string]interface {}{"age":25, "is_male":true, "name":"Hello 世界", "salary":8888.88}

    writer := bytes.NewBuffer(nil)

    // 创建编码器, 把编码结果写到 writer
    encoder := json.NewEncoder(writer)

    // encoder.SetEscapeHTML(true)
    // encoder.SetIndent(prefix, indent)

    // 编码 j
    _ = encoder.Encode(j)
    // 获取编码结果
    fmt.Printf("%s\n", writer.String())
    // {"age":25,"is_male":true,"name":"Hello 世界","salary":8888.88}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
你可以这样解析出 map 中的 fullDocument 中的 OwnerID、name、QuotaSize: ``` package main import ( "fmt" "reflect" ) func main() { m := map[string]interface{}{ "_id": map[string]interface{}{ "_data": "8263B4EB63000000062B022C0100296E5A1004C3E4524B77B64630AC204C7469FAED7F46645F6964006463B4EB636EBBDB249F2ED2770004", }, "clusterTime": map[string]interface{}{ "1672801123": 6, }, "documentKey": map[string]interface{}{ "_id": "ObjectID(\"63b4eb636ebbdb249f2ed277\")", }, "fullDocument": map[string]interface{}{ "OwnerID": 123, "QuotaSize": 104857600, "_id": "ObjectID(\"63b4eb636ebbdb249f2ed277\")", "directory": "/buckets", "name": "123_test1", }, "ns": map[string]interface{}{ "coll": "UserQuotaConfig", "db": "filer3", }, "operationType": "insert", "wallTime": 1672801123879, } // 取出 fullDocument fullDocument, ok := m["fullDocument"].(map[string]interface{}) if !ok { fmt.Println("fullDocument not found") return } // 取出 OwnerID OwnerID, ok := fullDocument["OwnerID"].(int) if !ok { fmt.Println("OwnerID not found") return } fmt.Println("OwnerID:", OwnerID) // 取出 name name, ok := fullDocument["name"].(string) if !ok { fmt.Println("name not found") return } fmt.Println("name:", name) // 取出 QuotaSize QuotaSize, ok := fullDocument["QuotaSize"].(int) if !ok { fmt.Println("QuotaSize not found") return } fmt.Println("QuotaSize:", QuotaSize) } ``` 在这个例子中,我们首先将 map 赋值给了变量 m。然后使用类型断言取出了 fullDocument 并将其赋

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谢TS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值