序列化需求
内存中的map、slice、array以及各种对象,如何保存到一个文件中? 如果是自己定义的结构体的实 例,如何保存到一个文件中? 如何从文件中读取数据,并让它们在内存中再次恢复成自己对应的类型的实例?
要设计一套协议,按照某种规则,把内存中数据保存到文件中。文件是一个字节序列,所以必须把数据 转换成字节序列,输出到文件。这就是序列化。 反之,从文件的字节序列恢复到内存并且还是原来的类 型,就是反序列化。
定义
serialization 序列化:将内存中对象存储下来,把它变成一个个字节。转为 二进制数据。
deserialization 反序列化:将文件的一个个字节恢复成内存中对象。从二进制数据中恢复。
序列化保存到文件就是持久化。
字符序列化:JSON、XML等。
二进制序列化:Protocol Buffers、MessagePack等。
可以将数据序列化后持久化,或者网络传输;也可以将从文件中或者网络接收到的字节序列反序列化。可以把数据和二进制序列之间的相互转换称为二进制序列化、反序列化,把数据和字符序列之间的相互转换称为字符序列化、反序列化。
JSON的数据类型
JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式。它基于1999年发布的 ES3 (ECMAScript是w3c组织制定的JavaScript规范)的一个子集,采用完全独立于编程语言的文本格 式来存储和表示数据。应该说,目前JSON得到几乎所有浏览器的支持。官网:http://json.org/
JSON是字符串,是文本。JavaScript引擎可以将这种字符串解析为某类型的数据。
object类型
无序键值对的集合
格式: {key1:value1, ... ,keyn:valulen} key必须是一个字符串,需要双引号。 value可以是任意合法的值。
array类型
有序的值的集合
格式:[val1,...,valn]
value类型
双引号引起来的字符串、数值、true和false、null、对象、数组,这些都是值
string类型
由双引号包围起来的任意字符的组合,可以有转义字符。
number类型
有正负,有整数、浮点数。
json包
Go标准库中提供了 encoding/json 包,内部使用了反射技术,效率较为低下。官网https://go.dev/blo g/json
json.Marshal(v any) ([]byte, error),将v序列化成字符序列(本质上也是字节序列),这个过程称 为Encode
json.Unmarshal(data []byte, v any) error,将字符序列data反序列化为v,这个过程称为Decode
基本类型序列化:
package main import ( "encoding/json" "fmt" ) func main() { // 定义一个any切片类型的变量,将各种类型都填进去 var data = []any{"牛逼abc", 123, 3.14, true, false, nil, map[int]string{}, [2]int{1, 11}, []string{"a", "b", "c"}, } target := [][]byte{} for _, v := range data { // 对各种类型的数据进行序列化,需提供任意类型的参数,返回字节序列和 // error。(v any) ([]byte, error) r, err := json.Marshal(v) if err != nil { fmt.Println(err) } // 序列化后,会得到字节序列 fmt.Printf("%T %[1]v ==> %T %[2]v\n", v, r) target = append(target, r) } // target为字节序列类型的切片 fmt.Println(target) fmt.Println("----反序列化----") // 对字节序列进行反序列化 var result any for _, v := range target { // 提供两个参数,第一个为字节序列,第二个为任意类型,用于接收反序列化后的值, // 类似Scan,需要用&来接收,返回error类型。(data []byte, v any) error err := json.Unmarshal(v, &result) if err != nil { fmt.Println(err) } fmt.Printf("%T %[1]v ==> %T %[2]v\n", v, result) } }示例1
下面为上面代码执行结果:
各种类型数据被序列化就成了字节序列,也可以说转换成了字符串。转换的结果都是字符串,但是这些字符串一旦交给JavaScript引擎,它能把它们转换 成对应的数据类型。
根据反序列化结果,从字符串(字节序列)反序列化为Go的某类型数据。JSON字符串中,数值被转换成了Go的float64类型;true、false转成了bool型; null转成了nil;字符串转成了string;数组转成了[]interface{}
结构体序列化:
package main import ( "encoding/json" "fmt" ) type Animal struct { // 对于使用 json.Marshal 进行序列化的字段,它们必须是公开的(首字母大写) Name string Age int } func main() { p0 := &Animal{"Tom", 20} r, err := json.Marshal(p0) if err != nil { fmt.Println(err) } fmt.Printf("%T %[1]v ==> %T %[2]v\n", p0, r) fmt.Printf("%v\n", string(r)) // 对其进行反序列化 var v0 any json.Unmarshal(r, &v0) // 反序列化后,成了map了 fmt.Printf("%T %[1]v\n", v0) // 可定义期望的类型的一个变量来进行接收,这样就变成期望的类型了 var v1 Animal json.Unmarshal(r, &v1) fmt.Printf("%T %[1]v\n", v1) }示例2
下面是上面代码执行结果:
切片序列化:
package main import ( "encoding/json" "fmt" ) func main() { s0 := make([]int, 3) r, err := json.Marshal(s0) if err != nil { fmt.Println(err) } fmt.Printf("%T %[1]v ==> %T %[2]v\n", s0, r) var v0 interface{} err = json.Unmarshal(r, &v0) if err != nil { fmt.Println(err) } fmt.Printf("%T %[1]v\n", v0) var v1 []int json.Unmarshal(r, &v1) fmt.Printf("%T %[1]v\n", v1) }示例3
下面是上面代码执行结果:
JSON序列化的Go实现效率较低,由此社区和某些公司提供大量开源的实现,例如easyjson、jsoniter、 sonic等。基本使用方式都兼容官方实现。
结构体字段标签
结构体的字段可以增加标签tag以供序列化、反序列化时使用
在字段类型后,可以跟反引号引起来的一个标签,用json为key,value用双引号引起来写,key与value直接使用冒号,这个标签中不要加入多余空格,否则语法错误。 例1:Name string `json:"name"`,这个例子序列化后得到的属性名为name,json表示json库使用;双引号内第一个参数用来指定字段转换使用的名称,多个参数使用逗号隔开
例2:Name string `json:"name,omitempty"`,omitempty为序列化时忽略空值,也就是该字段不序列化;空值为false、0、空数组、空切片、空map、空串、nil空指针、nil接口值 空数组、空切片、空串、空map,长度len为0,也就是容器没有元素。
如果使用 - ,该字段将被忽略 Name string `json:"-"`,序列化后没有该字段,反序列化也不会转换该字段,Name string `json:"-,"`,序列化后该字段显示但名为 "-" ,反序列化也会转换该字段
多标签使用空格间隔:Name string `json:"name,omitempty" msgpack:"myname"`
MessagePack
MessagePack是一个基于二进制高效的对象序列化类库,可用于跨语言通信。 它可以像JSON那样,在 许多种语言之间交换结构对象。但是它比JSON更快速也更轻巧。 支持Python、Ruby、Java、C/C++、 Go等众多语言。宣称比Google Protocol Buffers还要快4倍。MessagePack: It's like JSON. but fast and small. (msgpack.org),其基本使用方法和json包类似。
package main import ( "encoding/json" "fmt" "github.com/vmihailenco/msgpack/v5" ) type Animal struct { // 标签的各种写法 Name string `json:"name"` Age int `msgpack:"a"` // 在Color处的json标签对High字段进行空值忽略,结果发现Color字段也有效 Color string `json:"High,omitempty" msgpack:"-"` Weight string `msgpack:"-"` High float64 } func main() { p0 := &Animal{Name: "Tom", Age: 20} r0, _ := json.Marshal(p0) r1, _ := msgpack.Marshal(p0) fmt.Printf("%T %[1]v ==> %T %[2]v\n", p0, r0) fmt.Printf("%T %[1]v ==> %T %[2]v\n", p0, r1) fmt.Println(string(r0), string(r1)) // 反序列化 var v0 any json.Unmarshal(r0, &v0) fmt.Printf("%T %[1]v\n", v0) msgpack.Unmarshal(r0, &v0) fmt.Printf("%T %[1]v\n", v0) var v1 Animal json.Unmarshal(r0, &v1) fmt.Printf("%T %[1]v\n", v1) msgpack.Unmarshal(r0, &v1) fmt.Printf("%T %[1]v\n", v1) }示例4
下面是上面代码执行结果:
标签:语言,err,fmt,json,Printf,go,序列化,string From: https://www.cnblogs.com/caibao666/p/17540196.html