zoukankan      html  css  js  c++  java
  • Golang: 解析JSON数据之一

    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 文件,就会发现,配置内容已经更新了。

  • 相关阅读:
    题解 P3709 【大爷的字符串题】
    题解P2730 [USACO3.2]魔板 Magic Squares
    二维凸包
    题解 P2158 [SDOI2008]仪仗队
    搜索专题——DFS A1103 Integer Factorization(30)
    数据结构专题——链表处理A1097.Deduplication on a Linked List(25) (静态链表)
    数据结构专题——链表处理A1052.Linked List Sorting(25) (静态链表)
    数据结构专题——链表处理 A1032.Sharing (静态链表)
    数据结构专题——队列的应用 A1056.Mice and Rice ( 25)
    数据结构专题 ——栈的应用 A1051.Pop Sequence(25)
  • 原文地址:https://www.cnblogs.com/liuhe688/p/10971327.html
Copyright © 2011-2022 走看看