Golang 基础之json数据操作

2,512 阅读4分钟

使用内置库 encoding/json 处理几种常用的 json 数据格式

基础使用

内置库中 encoding/json,Go 代码中主要调用 Marshal 从数据结构生成JSON字符串的过程,并调用 Unmarshal 解析JSON的行为解组到数据结构。

函数原型

// 接收任意类型的k,v,返回JSON encoding 数据
func Marshal(v interface{}) ([]byte, error)
// 将json对象转成对应的数据结构
func Unmarshal(data []byte, v interface{}) error

读取

struct 结构体数据,转 json 格式
func structData() {
    type UserInfo struct {
        Name string `json:"name"` // 指定格式
        Age int `json:"age"`
    }
    user1 := &UserInfo{
        Name: "changhao",
        Age: 25,
    }
    res, err := json.Marshal(user1)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Printf("%s\n", res)
}
map数据,转 json格式
func mapData() {
    user := make(map[string]interface{})
    user["name"] = "changhao"
    user["age"] = 25
    res, err := json.Marshal(user)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Printf("%s\n", res)
}

用例,输出返回

{"age":25,"name":"changhao"}
使用 MarshalIndent 函数输出格式化 json

函数原型

func MarshalIndent(v interface{}, prefix, indent string) ([] byte , error)

MarshalIndent 类似于 Marshal,但应用 Indent 来格式化输出。根据缩进嵌套,输出中的每个 JSON 元素都将在以前缀开头的新行开始,后跟一个或多个缩进副本。

prefix 定义前缀字符, indent 设置缩进

func indentData(){
    user := make(map[string]interface{})
    user["name"] = "changhao"
    user["age"] = 25
    res, err := json.MarshalIndent(user, "", "    ")
    if err != nil {
        fmt.Println(err)
    }
    fmt.Printf("%s\n", res)
}

设置了4位空格缩进,用例输出结果

{
    "age": 25,
    "name": "changhao"
}

写入

首先将数据格式通过 json.MarshalIndent() 函数转成 json 对象, 在借助 ioutil.WriteFile() 函数写入文件,后缀务必为 .json

func writeJson() {
    type UserInfo struct {
        Name string `json:"name"`
        Age int `json:"age"`
        Hobby []string `json:"hobby"`
    }
    user := &UserInfo{
        Name: "changhao",
        Age: 25,
        Hobby: []string{"看书","学习新技术","编程"},
    }
    data, err := json.MarshalIndent(user, "", "    ")
    if err != nil {
        panic(err)
    }
    err = ioutil.WriteFile("data.json", data, 0755)
    if err != nil {
        panic(err)
    }
}

修改

针对刚刚写入的 data.json 文件, 在 Hobby 爱好列表中,新增一项 "玩游戏"

首先将通过 Unmarshal 函数读取json数据, 然后转成 map 数据类型。 删除后,在通过写入流程写入到json文件中。 至此修改完毕

func checkErr(err error) {
    if err != nil {
        panic(err)
    } 
}
​
func updateJson() {
    // 读取json数据
    data := make(map[string]interface{})
    file, err := ioutil.ReadFile("data.json")
    checkErr(err)
    err = json.Unmarshal(file, &data)
    checkErr(err)
    
    // 读取爱好列表, 新增新的爱好
    hobbyList := make([]string,0)
    for _, hobby := range data["hobby"].([]interface{}) {
        hobbyList = append(hobbyList, hobby.(string))
    }
    hobbyList = append(hobbyList, "玩游戏")
    data["hobby"] = hobbyList
    
    // 写入 data.json
    dataJson, err := json.MarshalIndent(data, "", "    ")
    checkErr(err)
    err = ioutil.WriteFile("data.json", dataJson, 0755)
    checkErr(err)
}

用例输出

{
    "age": 25,
    "hobby": [
        "看书",
        "学习新技术",
        "编程",
        "玩游戏"
    ],
    "name": "changhao"
}

删除

将 data.json 文件中,age 年龄字段删除

实现流程和修改功能一样。

func checkErr(err error) {
    if err != nil {
        panic(err)
    } 
}
​
func removeJson() {
    // 读取json数据
    data := make(map[string]interface{})
    file, err := ioutil.ReadFile("data.json")
    checkErr(err)
    err = json.Unmarshal(file, &data)
    checkErr(err)
    
    // 删除 key
    delete(data, "age")
​
    // 写入 data.json
    dataJson, err := json.MarshalIndent(data, "", "    ")
    checkErr(err)
    err = ioutil.WriteFile("data.json", dataJson, 0755)
    checkErr(err)
}

用例输出

{
    "hobby": [
        "看书",
        "学习新技术",
        "编程",
        "玩游戏"
    ],
    "name": "changhao"
}

业务场景

设计数据结构如下

{
    "list": [
        {"name": "小明", "age": 18},
        {"name": "小红", "age": 19},
    ],
}

场景一:map数据结构嵌套

写入

首先,定义数据结构,map写入数据。 调用 json.MarshalIndent 函数设置json格式,最后使用 ioutil.WriteFile 函数写入 json文件

func checkErr(err error) {
    if err != nil {
        panic(err)
    } 
}
​
func write() {
    // 创建json结构
    data := make(map[string]interface{})
    // 定义list 列表
    list := make([]map[string]interface{},0)
    // 定义类型
    type infoMap = map[string]interface{}
    info1 := make(infoMap)
    info1["name"] = "小明"
    info1["age"] = 18
    list = append(list, info1)
    info2 := make(infoMap)
    info2["name"] = "小红"
    info2["age"] = 19
    list = append(list, info2)
    data["list"] = list
​
    // 转换json数据格式
    dataJson, err := json.MarshalIndent(data, "", "    ")
    checkErr(err)
    // 写入json文件
    err = ioutil.WriteFile("data.json", dataJson, 0755)
    checkErr(err)
}

用例程序输出 data.json 文件

{
    "list": [
        {
            "age": 18,
            "name": "小明"
        },
        {
            "age": 19,
            "name": "小红"
        }
    ]
}
修改

首先,使用 ioutil.ReadFile函数 读取json文件,定义map结构体,用于接收Unmarshal 函数返回的 json对象,然后将列表中的小红、小明年龄统一修改为 20 岁。最后在调用 ioutil.WriteFile 函数将修改后的数据格式, 写入json文件

func checkErr(err error) {
    if err != nil {
        panic(err)
    } 
}
​
func update() {
    // 接收json结构
    data := make(map[string]interface{})
    file, err := ioutil.ReadFile("data.json")
    checkErr(err)
    err = json.Unmarshal(file, &data)
    checkErr(err)
    // 定义list 列表
    list := make([]map[string]interface{},0)
    for _, info := range data["list"].([]interface{}) {
        v := info.(map[string]interface{})
        v["age"] = 20
        list = append(list, v)
    }
    data["list"] = list
​
    // 转换json数据格式
    dataJson, err := json.MarshalIndent(data, "", "    ")
    checkErr(err)
    // 写入json文件
    err = ioutil.WriteFile("data.json", dataJson, 0755)
    checkErr(err)
}

用例程序输出 data.json 文件

{
    "list": [
        {
            "age": 20,
            "name": "小明"
        },
        {
            "age": 20,
            "name": "小红"
        }
    ]
}

场景二:结构体数据嵌套

实现思想和场景一相同, 主要将数据格式以结构体封装实现。

写入
func checkErr(err error) {
    if err != nil {
        panic(err)
    } 
}
​
func write() {
    // 定义结构体
    type ListItem struct {
        Name string `json:"name"`
        Age int `json:"age"`
    }
    type Info struct {
        List []ListItem `json:"list"`
    }
​
    // 写入数据
    var info Info
    item := make([]ListItem, 0)
    listItem1 := ListItem{
        Name: "小明",
        Age: 18,
    }
    item = append(item, listItem1)
​
    listItem2 := ListItem{
        Name: "小红",
        Age: 19,
    }
    item = append(item, listItem2)
    info.List = item
​
    data, err := json.MarshalIndent(info, "", "    ")
    checkErr(err)
    err = ioutil.WriteFile("data.json", data, 0755)
    checkErr(err)
}
修改
func checkErr(err error) {
    if err != nil {
        panic(err)
    } 
}
​
func update() {
    // 定义结构体
    type ListItem struct {
        Name string `json:"name"`
        Age int `json:"age"`
    }
    type Info struct {
        List []ListItem `json:"list"`
    }
​
    // 接收json结构
    var info Info
    file, err := ioutil.ReadFile("data.json")
    checkErr(err)
    err = json.Unmarshal(file, &info)
    checkErr(err)
    // 修改年龄
    itemList := make([]ListItem, 0)
    for _, item := range info.List {
        item.Age = 20
        itemList = append(itemList, item)
​
    }
    info.List = itemList
​
    // 写入json
    data, err := json.MarshalIndent(info, "", "    ")
    checkErr(err)
    err = ioutil.WriteFile("data.json", data, 0755)
    checkErr(err)
}