数据格式介绍
- 数据格式是系统中数据交互不可缺少的内容
- 这里主要介绍
JSON
、XML
、MSGPack
JSON
- json 是完全独立于语言的文本格式,是 k-v 的形式 name:zs
- 应用场景:前后端交互,系统间数据交互
- json 使用 go 语言内置的 encoding/json 标准库
编码 json 使用 json.Marshal()
函数可以对一组数据进行 JSON 格式的编码
生成 json 格式
通过结构体生成 JSON
需要格式化的结构体中的字段必须是一个外部可调用的字段(首写字母大写),否则再 json 包中无法识别则读取不到
输出的 jsonkey
是字段名称
package main import ( "encoding/json" "fmt" ) type Person struct { Name string Age int } func main() { p := &Person{"zs", 18} // 生成json b, err := json.Marshal(p) if err != nil { fmt.Println("json 序列化失败", err) return } fmt.Println(string(b)) // 格式化输出 b, err = json.MarshalIndent(p, "", " ") if err != nil { fmt.Println("json 格式化失败", err) return } fmt.Println(string(b)) }
struct tag
上面我们可以直接将结构体序列化为一个 json,但是发现 json 的key
是字段名称,不是我们想要的key
名称,这个怎么办呢?这里就需要用到 go 中的tag
特性了,我们再字段后添加一个json
tag 指定想要输出的key
名称即可。
package main import ( "encoding/json" "fmt" ) type Person struct { Name string `json:"name"` Age int `json:"age"` } func main() { p := &Person{"zs", 18} // 生成json b, err := json.Marshal(p) if err != nil { fmt.Println("json 序列化失败", err) return } fmt.Println(string(b)) }
通过 map 生成 json
package main import ( "encoding/json" "fmt" ) func main() { m := make(map[string]interface{}) m["name"] = "li" m["age"] = 18 m["sex"] = "男" b,err := json.Marshal(m) if err != nil { fmt.Println("json 序列化失败", err) return } fmt.Println(string(b)) }
解析 json 格式
解码 json 使用json.Unmarshal()
函数可以对一组数据进行 JSON 格式的解码
func Unmarshal(data []byte, v interface{}) error
解析到结构体
package main import ( "encoding/json" "fmt" ) type Person struct { Name string `json:"name"` //Age int `json:"int"` Age int `json:"int,string"` Sex string `json:"sex"` } func main() { //jsonData := []byte(`{"name":"zs","age":18,"sex":"男"}`) jsonData := []byte(`{"name":"zs","age":"18"","sex":"男"}`) var p Person err := json.Unmarshal(jsonData, &p) if err != nil { fmt.Println("反序列化失败", err) return } fmt.Println(p) }
解析到 interface
package main import ( "encoding/json" "fmt" ) type Person struct { Name string `json:"name"` Age int `json:"int"` Sex string `json:"sex"` } func main() { jsonData := []byte(`{"name":"zs","age":18,"sex":"男"}`) var i interface{} err := json.Unmarshal(jsonData, &i) if err != nil { fmt.Println("反序列化失败", err) return } fmt.Println(i) }
XML
- xml 是可扩展标记语言,包含声明、根标签、子元素和属性
- 应用场景:配置文件以及 webService
xml 文件示例
<?xml version="1.0" encoding="UTF-8" ?> <servers version="1"> <server> <serverName>Shanghai_VPN</serverName> <serverIP>127.0.0.1</serverIP> </server> <server> <serverName>Beijing_VPN</serverName> <serverIP>127.0.0.2</serverIP> </server> </servers>
解析和读取规则
golang 对 xml 的解析和读取是通过 stuct 和 refect 实现的,对于 struct 中的 tag 以什么方式对应到 xml 的元素上,golang 的文档中做了如下描述:
- 如果 struct 的一个字段是 string 或者[]byte 类型且它的 tag 含有",innerxml",Unmarshal 将会将此字段所对应的元素内所有内嵌的原始 xml 累加到此字段上
- 如果 struct 中有一个叫做 XMLName,且类型为 xml.Name 字段,那么在解析的时候就会保存这个 element 的名字到该字段
- 如果某个 struct 字段的 tag 定义中含有 XML 结构中 element 的名称,那么解析的时候就会把相应的 element 值赋值给该字段
- 如果某个 struct 字段的 tag 定义了中含有",attr",那么解析的时候就会将该结构所对应的 element 的与字段同名的属性的值赋值给该字段
- 如果某个 struct 字段的 tag 定义 型如"a>b>c",则解析的时候,会将 xml 结构 a 下面的 b 下面的 c 元素的值赋值给该字段
- 如果某个 struct 字段的 tag 定义了"-",那么不会为该字段解析匹配任何 xml 数据
- 如果 struct 字段后面的 tag 定义了",any",如果他的子元素在不满足其他的规则的时候就会匹配到这个字段
- 如果某个 XML 元素包含一条或者多条注释,那么这些注释将被累加到第一个 tag 含有",comments"的字段上,这个字段的类型可能是[]byte 或 string,如果没有这样的字段存在,那么注释将会被抛弃
读取 xml
package main import ( "encoding/xml" "fmt" "io/ioutil" ) // 抽取xml结构 type Server struct { ServerName string `xml:"serverName"` ServerIP string `xml:"serverIP"` } type Servers struct { XMLName xml.Name `xml:"servers"` Version xml.Attr `xml:"version,attr"` Servers []Server `xml:"server"` } func main() { data, err := ioutil.ReadFile("./test.xml") if err != nil { fmt.Println(err) return } var servers Servers err = xml.Unmarshal(data, &servers) if err != nil { fmt.Println(err) return } //fmt.Printf("%#v", servers) fmt.Printf("%v", servers) }
生成 xml
package main import ( "encoding/xml" "fmt" "io/ioutil" ) // 抽取xml结构 type Server struct { ServerName string `xml:"serverName"` ServerIP string `xml:"serverIP"` } type Servers struct { XMLName xml.Name `xml:"servers"` Version xml.Attr `xml:"version,attr"` Servers []Server `xml:"server"` } func main() { data, err := ioutil.ReadFile("./test.xml") if err != nil { println(err) return } var servers Servers err = xml.Unmarshal(data, &servers) if err != nil { println(err) return } //fmt.Printf("%#v", servers) fmt.Printf("%v\n", servers) // 将读取到的xml数据,通过xml.Marshal()方法再转换为xml格式 d, err := xml.Marshal(&servers) if err != nil { println(err) return } fmt.Println(string(d)) }
MSGPack
- MSGPack 是二进制的 json,性能更快,更省空间
- 需要安装第三方包:
go get -u github.com/vmihailenco/msgpack
package main import ( "fmt" "github.com/vmihailenco/msgpack" "io/ioutil" "math/rand" ) type Person struct { Name string Age int Sex string } // 写入json func writeJson(filename string) (err error) { var persons []*Person // 制作数据 for i := 0; i < 10; i++ { p := &Person{ Name: fmt.Sprintf("name%d", i), Age: rand.Intn(100), Sex: "male", } persons = append(persons, p) } // 二进制json格式化 data, err := msgpack.Marshal(persons) if err != nil { return } err = ioutil.WriteFile(filename, data, 0666) if err != nil { return } return } // 读取二进制json数据 func readJson(filename string) (persons []*Person, err error) { data, err := ioutil.ReadFile(filename) if err != nil { return } // 反序列化 err = msgpack.Unmarshal(data, &persons) if err != nil { return } return persons, err } func main() { //err := writeJson("./persons.json") //if err != nil { // fmt.Println(err) // return //} persons, err := readJson("./persons.json") if err != nil { fmt.Println(err) return } for _, v := range persons { fmt.Printf("%#v", v) } }
来源:https://www.cnblogs.com/zhichaoma/p/12509536.html