Go 序列化

admin
admin 2020年04月09日
  • 在其它设备中阅读本文章

应用程序的交互,即数据的交互,永远离不开序列化,常见的数据交互格式是 json。

一、Go 语言中的序列化和反序列化

go 语言中序列化对比:

方式 优点 缺点
binary 性能高 不支持不确定大小类型 int、slice、string
protobuf支持多种类型,性能高 需要单独存放结构,如果结构变动需要重新生成 .pb.go 文件
gob 支持多种类型 性能低
json 支持多种类型 性能低于 binary 和 protobuf
xml支持多种类型 性能低于 json

二、json

json 格式数据是现在数据交互用的最多的数据格式,go 一般通过 json.Marshal()进行序列化,通过 json.Unmarshal()反序列化。

type Message struct {
    Id   uint64 `json:"id"`
    Size uint64 `json:"size"`
    Data string `json:"data"`
}

func JsonEncodeDecode() {
    m1 := Message{3, 1024, "json"}
    var buf []byte
    var err error

    if buf, err = json.Marshal(m1); err != nil {
        log.Fatal("json marshal error:", err)
    }

    var m2 Message
    if err = json.Unmarshal(buf, &m2); err != nil {
        log.Fatal("json unmarshal error:", err)
    }
}

三、Gob

Gob(Go binary 的缩写)是 Go 语言自己以二进制形式序列化和反序列化程序数据的格式,其方法在 encoding 中,只能在 go 程序之间进行数据交互。

type Message struct {
    Id   uint64
    Size uint64
    Data string
}

func GobEncodeDecode() {
    m1 := Message{2, 1024, "gob"}
    var buf bytes.Buffer

    enc := gob.NewEncoder(&buf)
    dec := gob.NewDecoder(&buf)

    if err := enc.Encode(m1); err != nil {
        log.Fatal("encode error:", err)
    }

    var m2 Message
    if err := dec.Decode(&m2); err != nil {
        log.Fatal("decode error:", err)
    }
}

四、Binary

endoding 包中的 binnary 主要用于二进制数据序列化,但是局限性较高。
注意:数据类型必须是固定大小,如果字段中有不确定大小的类型,如 int,slice,string 等,则会报错。
字节序列方式(order):
binary.BigEndian(大端模式):内存的低地址存放着数据高位
binary.LittleEndian(小端模式):内存的低地址存放着数据地位

type Message struct {
    Id   uint64
    Size uint64
}

func BinaryRW() {
    m1 := Message{1, 1024}
    buf := new(bytes.Buffer)

    if err := binary.Write(buf, binary.LittleEndian, m1); err != nil {
        log.Fatal("binary write error:", err)
    }

    var m2 Message
    if err := binary.Read(buf, binary.LittleEndian, &m2); err != nil {
        log.Fatal("binary read error:", err)
    }
}

五、Protobuf

ProtoBuf 并不是 go 语言中包自带的,需要自行安装 protoc 编译器,以及 protoc 库以及生成相关的类

syntax = "proto2";
package example;

message Message {
    required uint64 id = 1;
    required uint64 size = 2;
    required string data = 3;
}
func ProtoEncodeDecode() {
    m1 := &example.Message{
        Id:   proto.Uint64(4),
        Size: proto.Uint64(1024),
        Data: proto.String("proto"),
    }

    buf, err := proto.Marshal(m1)
    if err != nil {
        log.Fatal("proto marshal error:", err)
    }

    var m2 example.Message
    if err = proto.Unmarshal(buf, &m2); err != nil {
        log.Fatal("proto unmarshal error:", err)
    }
    fmt.Println(m2.GetId(), m2.GetSize(), m2.GetData())
}

六、XML

Go 语言内置的 encoding/xml 包可以用在结构体和 XML 格式之间进行编解码,其方式跟 encoding/json 包类似

type Message struct {
    Id   uint64
    Size uint64
    Data string
}

func XmlEncodeDecode() {
    m1 := Message{2, 1024, "gob"}
    var buf bytes.Buffer

    enc := xml.NewEncoder(&buf)
    dec := xml.NewDecoder(&buf)

    if err := enc.Encode(m1); err != nil {
        log.Fatal("encode error:", err)
    }

    var m2 Message
    if err := dec.Decode(&m2); err != nil {
        log.Fatal("decode error:", err)
    }
}