为了让数据结构能够在网络中传输或保存到文件,它必须被编码后再解码。目前有多种可用的编码方式,比如JSON、XML、Google的Protocol Buffers等。
Gob(go binary)是Golang自己以二进制形式序列化和反序列化程序数据的格式,位于encoding/gob
包中。类似于Python中的pickle
和Java中Serialization
。
-
gob
可用于传递远端程序调用(RPC)的参数和结果。 -
encoding/gob
包实现了高效地序列化,特别是数据结构负责的,比如结构体、数字、切片。 -
encoding/gob
用于管理gob
流,gob
流是指在编码器(发送器,encoder)和解码器(接收器,decoder)之间交换的字节流数据。
Gob和JSON一样由发送端使用Encoder
对数据结构进行编码,当接收端接收到消息后使用Decoder
将序列化的数据转换为本地变量。
Golang可通过JSON或Gob来序列化Struct对象,虽然JSON的序列化更为通用,但利用Gob编码可以实现JSON所不能支持的Struct的方法序列化,利用Gob包序列化Struct保存到本地会十分简单。
Gob不是可外部定义且语言无关的编码方式,首选的是二进制格式,不像JSON或XML的文本格式。
Gob并不是一种不同于Go的语言,而是在编码和解码过程中用到Go的反射。
Gob可用于远程方法调用(RPC)参数和结果的传输,以及应用程序和机器之间的数据传输。
Gob只能用于纯Go环境中,例如两个使用Golang编写的服务之间的通信,以实现更加高效和优化。
Gob文件或流是完全自描述的,它里面包含的所有类型都有一个对应的描述,且都是可用Go语言解码,而无需了解文件的内容。
编码器 gob.NewEncoder
-
gob.NewEncoder
接口参数w
需实现io.Writer
接口类型
func NewEncoder(w io.Writer) *Encoder {
enc := new(Encoder)
enc.w = []io.Writer{w}
enc.sent = make(map[reflect.Type]typeId)
enc.countState = enc.newEncoderState(new(encBuffer))
return enc
}
编码 encoder.Encode
func (enc *Encoder) Encode(e interface{}) error {
return enc.EncodeValue(reflect.ValueOf(e))
}
Gob序列化
Gob
使用io.Writer
接口会通过NewEncoder()
函数创建Encoder
对象,通过调用Encoder
对象的Encode()
方法实现编码操作。
创建结构体
type User struct{
Id int
Name string
}
编码序列化,结构体转换为bytes.Buffer
,编码生成字节切片。
user := &User{Id:1, Name:"root"}
buf := new(bytes.Buffer)
encoder := gob.NewEncoder(buf)//创建编码器
err := encoder.Encode(user)//编码
if err!=nil {
panic(err)
}
fmt.Printf("%x\n", buf.Bytes())
22ff81030101045573657201ff820001020102496401040001044e616d65010c0000000bff8201020104726f6f7400
封装编码生成字节切片
func encode(obj interface{}) (*bytes.Buffer, error){
buf := new(bytes.Buffer)
encoder := gob.NewEncoder(buf)
err := encoder.Encode(obj)
if err!=nil{
return nil, err
}
return buf, err
}
编码生成字节缓存并保存到磁盘文件
//write gob序列化后写入文件
func write(data interface{}, filename string) (*bytes.Buffer, error){
buf := new(bytes.Buffer)
encoder := gob.NewEncoder(buf)
err := encoder.Encode(data)
if err!=nil{
return nil, err
}
err = ioutil.WriteFile(filename, buf.Bytes(), 0600)
if err!=nil{
return nil, err
}
return buf, err
}
创建Gob文件
要使用Gob,首先需要通过NewEncoder()
方法创建一个编码器,并向其提供一系列数据,然后再接收端通过调用NewDecoder()
方法创建一个解码器,从数据流中恢复数据并将其填入本地变量中。
//write gob序列化后写入文件
func write(data interface{}, filename string) error{
file,err := os.OpenFile(filename, os.O_RDWR | os.O_CREATE, 0777)
if err!=nil{
return err
}
defer file.Close()
encoder := gob.NewEncoder(file)
err = encoder.Encode(data)
if err!=nil{
return err
}
return nil
}
user := &User{Id:1, Name:"root"}
write(user, "user.gob")
解码器gob.NewDecoder
func NewDecoder(r io.Reader) *Decoder {
dec := new(Decoder)
// We use the ability to read bytes as a plausible surrogate for buffering.
if _, ok := r.(io.ByteReader); !ok {
r = bufio.NewReader(r)
}
dec.r = r
dec.wireType = make(map[typeId]*wireType)
dec.decoderCache = make(map[reflect.Type]map[typeId]**decEngine)
dec.ignorerCache = make(map[typeId]**decEngine)
dec.countBuf = make([]byte, 9) // counts may be uint64s (unlikely!), require 9 bytes
return dec
}
反序列化decoder.Decode
func (dec *Decoder) Decode(e interface{}) error {
if e == nil {
return dec.DecodeValue(reflect.Value{})
}
value := reflect.ValueOf(e)
// If e represents a value as opposed to a pointer, the answer won't
// get back to the caller. Make sure it's a pointer.
if value.Type().Kind() != reflect.Ptr {
dec.err = errors.New("gob: attempt to decode into a non-pointer")
return dec.err
}
return dec.DecodeValue(value)
}
//反序列化
reader := bytes.NewReader(bs.Bytes())
decoder := gob.NewDecoder(reader)
var u User
err = decoder.Decode(&u)
if err!=nil{
panic(err)
}
fmt.Println(u) //{1 root}
读取Gob文件
file,err := os.Open("user.gob")
if err!=nil{
panic(err)
}
decoder := gob.NewDecoder(file)
var user User
err = decoder.Decode(&user)
if err!=nil{
panic(err)
}
fmt.Println(user)//{1 root}