Go gob

JunChow520 · · 1479 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

为了让数据结构能够在网络中传输或保存到文件,它必须被编码后再解码。目前有多种可用的编码方式,比如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}

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:JunChow520

查看原文:Go gob

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1479 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传