一尘不染

结构到磁盘的有效Go序列化

go

我的任务是将C ++代码替换为Go,我对Go API还是很陌生。我正在使用gob对磁盘页面上的数百个键/值条目进行编码,但是gob编码不需要太多膨胀。

package main

import (
    "bytes"
    "encoding/gob"
    "fmt"
)
type Entry struct {
    Key string
    Val string
}

func main() {
    var buf bytes.Buffer
    enc := gob.NewEncoder(&buf)
    e := Entry { "k1", "v1" }
    enc.Encode(e)
    fmt.Println(buf.Bytes())
}

这产生了很多我不需要的膨胀:

[35 255 129 3 1 1 5 69 110 116 114 121 1 255 130 0 1 2 1 3 75 101 121 1 12 0 1 3 86 97 108 1 12 0 0 0 11 255 130 1 2 107 49 1 2 118 49 0]

我想序列化每个字符串的len,然后再序列化原始字节,例如:

[0 0 0 2 107 49 0 0 0 2 118 49]

我保存了数百万个条目,因此编码中的额外膨胀使文件大小增加了大约10倍。

没有手动编码,如何将其序列化为后者?


阅读 240

收藏
2020-07-02

共1个答案

一尘不染

使用protobuf有效地编码您的数据。

https://github.com/golang/protobuf

您的主体看起来像这样:

package main

import (
    "fmt"
    "log"

    "github.com/golang/protobuf/proto"
)

func main() {
    e := &Entry{
        Key: proto.String("k1"),
        Val: proto.String("v1"),
    }
    data, err := proto.Marshal(e)
    if err != nil {
        log.Fatal("marshaling error: ", err)
    }
    fmt.Println(data)
}

您可以这样创建一个文件example.proto:

package main;

message Entry {
    required string Key = 1;
    required string Val = 2;
}

您可以通过运行以下命令从原始文件生成go代码:

$ protoc --go_out=. *.proto

您可以根据需要检查生成的文件。

您可以运行并查看结果输出:

$ go run *.go
[10 2 107 49 18 2 118 49]
2020-07-02