google做到protobuf很多人都用过,但是google还有一个类似的产品,FlatBuffer。
区别在于pbf做了压缩,传输量比较小,编解码相对比较快,与rapidjson类似,而FlatBuffer并不压缩,所以编解码更快,但是数据量也会更大;
Flatbuffer产生一个很小的头文件,编码的方式是半手动的,使用方式和rapidjson很象,但是函数设计的更加恶心。但是有些时候必须要用,比如改造的项目!
首先我们写一个定义文件proto.fbs
namespace Msg;
table Block {
id: long;
hash: string;
children: [Tx];
}
table Tx {
name: string;
hash: string;
value: double;
}
root_type Block;
使用编译一下,生成相关的文件:
./flatc.exe -g ./pro.fbs
生成了一个目录,Msg里面有2个文件,
还需要下载相关的库:
go get -v github.com/google/flatbuffers/go
备注:某些时候不好下载,使用移动热点;
写一个编码的测试文件:
package main
// ./flatc.exe -g ./pro.fbs
import (
"fmt"
fbs "./Msg"
flatbuffers "github.com/google/flatbuffers/go"
)
type Tx struct {
Name string
Hash string
Value float64
}
type Block struct {
Id int64
Hash string
Children []Tx
}
func DecodeToBlock(buf []byte) Block {
var (
block Block
)
// buf, err := ioutil.ReadFile(filename)
// if err != nil {
// panic(err)
// }
//传入二进制数据
b := fbs.GetRootAsBlock(buf, 0)
block.Hash = string(b.Hash())
block.Id = b.Id()
len := b.ChildrenLength()
for i := 0; i < len; i++ {
tx_f := new(fbs.Tx)
tx := new(Tx)
if b.Children(tx_f, i) {
tx.Hash = string(tx_f.Hash())
tx.Value = tx_f.Value()
}
//append(block.Children, *tx)
fmt.Println("child:", tx)
}
return block
}
func main() {
tx1 := Tx{Name: "robin", Hash: "0", Value: 123}
tx2 := Tx{Name: "fox", Hash: "1", Value: 456}
block := Block{Id: 1, Hash: "2"}
//初始化buffer,大小为0,会自动扩容
builder := flatbuffers.NewBuilder(0)
//第一个交易cd
tx1_hash := builder.CreateString(tx1.Hash)
fbs.TxStart(builder)
fbs.TxAddHash(builder, tx1_hash)
fbs.TxAddValue(builder, tx1.Value)
ntx1 := fbs.TxEnd(builder)
//第二个交易
tx2_hash := builder.CreateString(tx2.Hash)
fbs.TxStart(builder)
fbs.TxAddHash(builder, tx2_hash)
fbs.TxAddValue(builder, tx2.Value)
ntx2 := fbs.TxEnd(builder)
//block
//先处理数组,string等非标量
fbs.BlockStartChildrenVector(builder, 2)
builder.PrependUOffsetT(ntx1)
builder.PrependUOffsetT(ntx2)
txs := builder.EndVector(2)
//再处理标量
b1_hash := builder.CreateString(block.Hash)
fbs.BlockStart(builder)
fbs.BlockAddId(builder, block.Id)
fbs.BlockAddHash(builder, b1_hash)
fbs.BlockAddChildren(builder, txs)
nb1 := fbs.BlockEnd(builder)
builder.Finish(nb1)
buf := builder.FinishedBytes() //返回[]byte
fmt.Println(buf)
DecodeToBlock(buf)
}
备注:在文件开始,我们定义了结构体,并作为实体类使用;而自动生成的类无法这样使用,仅仅能用来辅助序列化而已,真是太恶心了;还不如某些json库好用;
这里每个字符串都需要提起生成,然后把偏移添加到builder里,而浮点数不需要;