个人对flatbuffer与protobuf的比较:flatbuffer比protobuf好用一个数量级,相见恨晚。从schema文件的编写,编译,python/c++对buf文件的操作,引入flatbuffer代码的第三方依赖和构建,都超级简单流畅!
代码库
GitHub - google/flatbuffers: FlatBuffers: Memory Efficient Serialization Library
教程
FlatBuffers: Using the schema compiler
编译选项
可以下载代码库里面预编译好的二进制flatc编译schema文件,无需构建flatbuffer代码。
编译scama文件生成C++定义
flatc --cpp --gen-object-api ./schema.fbs
生成头文件schema_generated.h
编译scama文件生成python定义
flatc --python --gen-object-api ./schema.fbs
pip install flatbuffers==2.0.0 #安装对应版本pip包,结合上面编译生成的python代码即可对模型进行操作
加上--gen-object-api选项后可以基于native类型进行对象定义,然后基于pack和unpack创建flatbuf对象,然后进行序列化和反序列化,超级方便。
跟python交互时数组支持numpy转换,非常方便。
用户的源码只需要include生成的这个文件,搭配flatbuffers/include/里面的头文件即可使用,不需要编译flatbuffer生成so文件,比protobuf方便太多。加上使用预编译好的flatc二进制,使用flatbuf不需要编译依赖库,以及依赖其他第三方!
flatc把二进制序列化的flatbuf文件转化为json文件:
# flatc --raw-binary -t <path to fbs schema file> -- <path to flatbuffer binary file>
../flatc --raw-binary -t monster.fbs -- Monster.bin
FlatBuffers反射 - HarmonyHu’s Blog
flac生成源码时需要加上--gen-object-api,则
1)每个table都会生成对象结构体,(T结尾符),该结构体可以直接进行数据操作;
2)每个table新增UnPack/UnpackTo/Pack方法,进行对象结构体与table结构体间的转换。
可以用CreateXXX方法创建对象。
使用方法
// 反序列化成object结构体
auto moster = GetMoster(flatbuffer);
MonsterT * monsterObj = moster->UnpackTo();
...
delete monsterObj;
// Autogenerated class from table Monster.
MonsterT monsterobj;
// Deserialize from buffer into object.
GetMonster(flatbuffer)->UnPackTo(&monsterobj);
// 序列化成table结构体
MonsterT monsterObj;
monsterObj->name = "Bob";
FlatBufferBuilder builder;
Pack(builder, &monsterObj);
附:flatc选项
--cpp : 生成xxxx_generate.h的c++源文件
--gen-mutable : 每个table生成可以修改的方法
--gen-name-strings : 每个table生成GetFullyQualifiedName方法,返回路径名,如:MySample.Monster
--reflect-names : 每个table生成MiniReflectTypeTable方法,返回TypeTable *,包含每个成员名及成员属性
--gen-object-api: 每个table生成对象类,且生成pack和unpack方法,进行序列化和反序列化
序列化和反序列化
序列化
MonsterT monsterobj;
// Update object directly like a C++ class instance.
cout << monsterobj.name; // This is now a std::string!
monsterobj.name = "Bob"; // Change the name.
// Serialize into new flatbuffer.
FlatBufferBuilder fbb;
fbb.Finish(Monster::Pack(fbb, &monsterobj));
uint8_t *buf = builder.GetBufferPointer();
int size = builder.GetSize(); // Returns the size of the buffer that GetBufferPointer() points to.
反序列化
inline const MyGame::Sample::Monster *GetMonster(const void *buf)
python加载模型
from MyGame.Sample.Monster import Monster as example
# import flatbuffers
buf = open('Monster.bin', 'rb').read()
buf = bytearray(buf)
monster = example.GetRootAsMonster(buf, 0)
with open('Monster.bin', 'rb') as f:
buf = f.read()
buf = bytearray(buf)
monster = Monster.GetRootAsMonster(buf, 0)
monster_t = MonsterT.InitFromObj(monster)
builder = flatbuffers.Builder()
lite_graph = graph_t.Pack(builder)
builder.Finish(lite_graph)
buf = builder.Output()
with open(out_model_path, mode="wb") as f:
f.write(buf)
schema文件
如何开发schema文件
如何生成和保存,加载模型文件,二进制和文本文件
fbs里面还可以include其他fbs文件
include "xxx.fbs";
定义多个root_type, 可以考虑在原来的schema基础上创建新的,引用之前的并且定义新的root_type。
include "schema.fbs";
namespace xxx;
root_type yyy;