FlatBuffers 是一个序列化开源库,实现了与 Protocol Buffers,Thrift,Apache Avro,SBE 和 Cap'n Proto 类似的序列化格式,主要由 Wouter van Oortmerssen 编写,并由 Google 开源。Oortmerssen 最初为 Android 游戏和注重性能的应用而开发了FlatBuffers。现在它具有C ++,C#,C,Go,Java,PHP,Python 和 JavaScript 的端口。
FlatBuffer 是一个二进制 buffer,它使用 offset 组织嵌套对象(struct,table,vectors,等),可以使数据像任何基于指针的数据结构一样,就地访问数据。然而 FlatBuffer 与大多数内存中的数据结构不同,它使用严格的对齐规则和字节顺序来确保 buffer 是跨平台的。此外,对于 table 对象,FlatBuffers 提供前向/后向兼容性和 optional 字段,以支持大多数格式的演变。
FlatBuffers 的主要目标是避免反序列化。这是通过定义二进制数据协议来实现的,一种将定义好的将数据转换为二进制数据的方法。由该协议创建的二进制结构可以 wire 发送,并且无需进一步处理即可读取。相比较而言,在传输 JSON 时,我们需要将数据转换为字符串,通过 wire 发送,解析字符串,并将其转换为本地对象。Flatbuffers 不需要这些操作。你用二进制装入数据,发送相同的二进制文件,并直接从二进制文件读取。
通过flatc 编译schema文件描述的数据结构,生成序列化和反序列化的文件,可以直接使用该文件。
对tensorflow lite而言,已经得到序列化后的的模型文件,从中解析出 tensor(训练出的参数)和操作符等,然后让输入数据流过解析出的固化网络,经过各种运算后得到输出。
flatbuffers/samples: flatbuffers官方提供的demo 路径;
http://google.github.io/flatbuffers/flatbuffers_guide_use_cpp.html
https://github.com/google/flatbuffers/blob/master/samples/sample_binary.cpp
FlatBuffers 支持的数据结构有:基本类型和复杂类型。
基本类型:
8 bit: byte ubyte bool
16 bit: short ushort
32 bit: int uint float
64 bit: long ulong double
3 个特殊的类型:SOffsetT、UOffsetT、VOffsetT。
SOffsetT 存储的是一个有符号的 offset,
UOffsetT 存储的是数组数据的无符号的 offset,
VOffsetT 存储的是 vtable 中的无符号的 offset。
SOffsetT int32,它的 size = 4;UOffsetT uint32,它的 size = 4;VOffsetT uint16,它的 size = 2。
复杂类型:
数组 (用中括号表示 [type]). 不支持嵌套数组,可以用table实现
字符串 string, 支持 UTF-8 或者 7-bit ASCII. 对于其他编码可以用数组 [byte]或者[ubyte]表示。
Struct 只支持基本类型或者嵌套Struct
Table 类似Struct,但是可以支持任何类型。
基本的数据类型,只有标量值可以有默认值,非标量(string/vector/table)字段默认不存在时为null。
其中数据类型table最为灵活常用,可以向前后兼容,table的seriale也最复杂。
请参考
http://coolpers.github.io/android/2016/03/14/android-flatbuffers-brief.html
编译安装工具flatc工具
首先要先装Cmake(apt install cmake)
(1)下载FlatBuffers源码,从gitHub上下载项目源代码:
git clone https://github.com/google/flatbuffers.git
(2)进入flatbuffers项目根目录,输入如下命令
cmake -G "Unix Makefiles" //生成MakeFile
make //生成flatc
make install //安装flatc
(3)查看flatc
➜ flatbuffers git:(master) flatc --version
flatc version 1.10.0
./include/flatbuffers/flatbuffers.h
➜ flatbuffers git:(master) pwd
/home/ws/code/flatbuffers/include/
g++ -std=c++11 ./test.cpp -I /home/ws/code/flatbuffers/include/
namespace TestApp;
struct KV {
key: ulong;
value: double;
}
table TestObj {
id:ulong;
name:string;
flag:ubyte = 0;
list:[ulong];
kv:KV;
}
root_type TestObj;
#include "test_generated.h"
#include <vector>
#include <iostream>
using namespace std;
using namespace TestApp;
int main()
{
flatbuffers::FlatBufferBuilder builder;
/////////// Serialize //////////
// Create list
std::vector<uint64_t> vec;
for(size_t i=0;i<10;i++)
{
vec.push_back(i);
}
// Create flat buffer inner type
auto id = 123;
auto name = builder.CreateString("name");
auto list = builder.CreateVector(vec); // vector
uint8_t flag = 1;
auto kv = KV(1, 1.0); // struct
// table
auto mloc = CreateTestObj(builder, id, name, flag, list, &kv);
builder.Finish(mloc);
char* ptr = (char*)builder.GetBufferPointer();
>> uint64_t size = builder.GetSize();
////////// Deserialize //////////
auto obj = GetTestObj((uint8_t*)ptr);
cout << obj->id() << endl;
cout << obj->name()->c_str() << endl;
cout << obj->flag() << endl;
for(size_t i=0;i<obj->list()->size();i++)
{
cout << obj->list()->Get(i) << endl;
}
// can use assign to std::vector for speed up
// vec.reserve(obj->list()->size());
// vec.assign(obj->list()->begin(), obj->list()->end());
cout << obj->kv()->key() << endl;
cout << obj->kv()->value() << endl;
}
➜ learning_test g++ -std=c++11 ./test.cpp -I /home/ws/code/flatbuffers/include/
➜ learning_test ./a.out
123
name
//这里为什么是乱码?
0
1
2
3
4
5
6
7
8
9
1
1
其中g++ -std=c++11 ./test.cpp -I /home/ws/code/flatbuffers/include/
参数 -I 指的是 "flatbuffers/flatbuffers.h"所在路径 (编译依赖flatbuffers的源码)
#include "flatbuffers/flatbuffers.h"
namespace TestApp {