ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

FlatBuffers 快速入门:从 schema 定义到跨语言序列化与反序列化实战

FlatBuffers 快速入门:从 schema 定义到跨语言序列化与反序列化实战 FlatBuffers 快速入门从 schema 定义到跨语言序列化与反序列化实战【免费下载链接】flatbuffersFlatBuffers: Memory Efficient Serialization Library项目地址: https://gitcode.com/GitHub_Trending/fl/flatbuffersFlatBuffers 是一款零拷贝、内存高效的序列化库与 JSON、Protocol Buffers 等传统方案不同它不需要在读取时解析数据而是直接通过偏移量访问内存中的字段因此天然适合游戏、高频网络通信等对延迟敏感的场景。本文基于官方 Quick Start 文档带领你完成一次完整的 FlatBuffers 使用闭环编译flatc编译器、编写.fbs模式文件、生成多语言代码、构造并序列化数据、传输存储以及跨语言反序列化读取——全部步骤均可直接在当前仓库中验证。1. 整体流程一览FlatBuffers 的使用分为六个核心步骤后续各节将逐一展开构建 FlatBuffers 编译器flatc编写定义数据结构的模式文件.fbs用flatc为你的目标语言生成代码结合生成代码与FlatBufferBuilder序列化数据传输或存储序列化后的缓冲区用生成访问器读取数据——不必使用同一语言甚至不必使用同一 schema 版本。其中步骤 4 到 6 是 FlatBuffers 与传统序列化方案的核心差异点数据写入后即可被任意语言、任意演进版本直接读取详见 evolution.md。2. 构建 flatc 编译器flatc是 FlatBuffers 的主编译器负责把模式定义转换为多种语言的生成代码文件参见 flatc.md。使用 CMake 在类 Unix 平台构建cmake -G Unix Makefiles make -j更贴近生产环境的方式是显式指定构建类型参见 building.mdcmake -G Unix Makefiles -DCMAKE_BUILD_TYPERelease make -j构建完成后当前目录下会生成flatc可执行文件。仓库的 CMakeLists.txt 是项目的总构建入口编译器的主程序源码位于 src/flatc_main.cpp。提示默认配置下 CMake 不会开启严格警告模式如-Werror//WX。若需要提交代码或对齐 CI 要求可追加-DFLATBUFFERS_STRICT_MODEON开启。3. 定义 FlatBuffer 模式.fbsFlatBuffers 使用自有的 IDL接口定义语言描述数据结构文件后缀为.fbs。以 Quick Start 中的最小示例为例table Monster { name:string; health:int; } root_type Monster;table是 FlatBuffers 中组织数据的主要结构可以在不破坏兼容性的前提下随时间增删字段root_type声明序列化数据的根表这对 JSON 解析尤为重要因为 JSON 本身不包含对象类型信息。仓库中的完整示例见 samples/monster.fbs它展示了模式语言的更多要素namespace MyGame.Sample; enum Color:byte { Red 0, Green, Blue 2 } union Equipment { Weapon } struct Vec3 { x:float; y:float; z:float; } table Monster { pos:Vec3; mana:short 150; hp:short 100; name:string; friendly:bool false (deprecated); inventory:[ubyte]; color:Color Blue; weapons:[Weapon]; equipped:Equipment; path:[Vec3]; } table Weapon { name:string; damage:short; } root_type Monster;各要素的简要说明详见 schema.mdnamespace把生成代码放入对应命名空间/包中支持用.表示嵌套。enum一组具名常量可指定底层整数类型上例为byte未显式赋值的项自动递增。struct仅由标量或其它 struct 组成的紧凑结构内联存储、无 vtable访问最快但定义后不可增删字段。table可演化的主数据结构字段可加默认值如mana:short 150。union一组候选 table 类型中的某一个序列化时同时生成类型字段与值字段。[type]向量vector类型[ubyte]表示字节数组[Weapon]表示对象数组。(deprecated)标记字段弃用后续代码不再生成访问器但旧数据仍可被读取。root_type声明根表配合file_identifier XXXX恰 4 字符可在缓冲区偏移 4–7 处写入魔数标识。3.1 字段缺省时的三种行为schema 中的字段并非必须写入二进制数据其缺省行为分为三种相互排斥详见 schema.md模式声明方式读取行为默认值mana:short 150;返回 schema 中声明的默认值未声明时为标量0或其它类型null可选hp:short null;返回语言原生 optional 类型如 C 的std::optionalT必填hp:short (required);缺失即校验失败整个缓冲区被 verifier 判为无效注意等于默认值的字段不会真正写入序列化数据这是 FlatBuffers 节省空间的重要机制因此不要随意修改已发布 schema 的默认值否则新旧代码会读到不一致的结果。4. 生成语言代码使用flatc将 schema 转换为目标语言代码./flatc --cpp --rust monster.fbs上述命令会生成monster_generated.h和monster_generated.rs两个文件。flatc的通用调用形式为参见 flatc.mdflatc [ GENERATOR_OPTIONS ] [ -o PATH ] [ -I PATH ] FILES... [ -- BINARY_FILES... ]GENERATOR_OPTIONS指定目标语言及开关选项-o PATH指定生成文件输出目录缺省为当前目录-I PATH指定include语句搜索路径缺省为当前目录。支持的语言生成器包括--cpp、--java、--kotlin、--csharp、--go、--python、--js、--ts、--php、--dart、--lua、--lobster、--rust、--swift、--nim追加--grpc还可生成 gRPC 桩代码。常用附加选项还有--gen-mutable生成就地修改 FlatBuffer 的非 const 访问器--gen-object-api额外生成基于对象的 API更易构造/修改代价是额外对象分配--gen-all连同include的所有 schema 一起生成代码--filename-suffix SUFFIX自定义生成文件名后缀默认为_generated--conform FILE校验后续 schema 是否为FILE的合法演进返回0表示符合演进规则。4.1 附加JSON 与二进制互转flatc还能完成数据文件转换同样见 flatc.md# JSON → 二进制schema 需排在数据文件之前 flatc --binary myschema.fbs mydata.json # 二进制 → JSON无 file_identifier 时需加 --raw-binary flatc --json myschema.fbs -- mydata.bin第一条命令会生成mydata_wire.bin第二条生成mydata.json。这正是 monsterdata_test.json 与 monsterdata_test.mon 这类测试数据的产生方式。5. 序列化数据生成代码后配合运行库中的FlatBufferBuilder构造缓冲区。Quick Start 的最小示例#include flatbuffers.h #include monster_generated.h int main() { // Used to build the flatbuffer FlatBufferBuilder builder; // Auto-generated function emitted from flatc and the input // monster.fbs schema. auto monster CreateMonsterDirect(builder, Abominable Snowman, 100); // Finalize the buffer. builder.Finish(monster); }CreateMonsterDirect是flatc根据monster.fbs自动生成的便捷构造函数。仓库中的完整 C 示例 samples/sample_binary.cpp 展示了更真实的构建流程先构造嵌套对象武器、再构造字符串与向量、最后组装根对象flatbuffers::FlatBufferBuilder builder; // 1. 先构造被引用的对象武器 auto sword CreateWeapon(builder, builder.CreateString(Sword), 3); auto axe CreateWeapon(builder, builder.CreateString(Axe), 5); // 2. 构造向量武器的 offsets std::vectorflatbuffers::OffsetWeapon weapons_vector { sword, axe }; auto weapons builder.CreateVector(weapons_vector); // 3. 构造其余数据 auto position Vec3(1.0f, 2.0f, 3.0f); auto name builder.CreateString(MyMonster); unsigned char inv_data[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; auto inventory builder.CreateVector(inv_data, 10); // 4. 组装根对象并 Finish auto orc CreateMonster(builder, position, 150, 80, name, inventory, Color_Red, weapons, Equipment_Weapon, axe.Union()); builder.Finish(orc);构建顺序遵循 FlatBuffers 的自底向上模型所有被引用的对象必须先于引用者创建。Finish()完成缓冲区收尾其实现位于 include/flatbuffers/flatbuffer_builder.h可在根对象上附带可选的file_identifier。6. 传输与存储缓冲区一旦Finish即可自由使用发送给远端、落盘保存、放入消息队列皆可。获取指向缓冲区的指针// Get a pointer to the flatbuffer. const uint8_t* flatbuffer builder.GetBufferPointer();配套方法还有builder.GetSize()缓冲区字节数两者在 include/flatbuffers/flatbuffer_builder.h 与 include/flatbuffers/flatbuffer_builder.h 中声明。完整的收发循环可参考仓库中的网络示例 examples/go-echo。7. 跨语言读取数据读取时无需解析——生成的访问器直接按偏移量访问内存。即使读取方与写入方语言不同、schema 版本不同FlatBuffers 也保证数据可读前提是遵循 evolution.md 中的演进规则。// Get a view of the root monster from the flatbuffer. const Monster snowman GetMonster(flatbuffer); // Access the monsters fields directly. ASSERT_EQ(snowman-name(), Abominable Snowman); ASSERT_EQ(snowman-health(), 100);GetMonster(flatbuffer)是flatc生成的根访问函数。完整的验证式读取逻辑见 samples/sample_binary.cpp它覆盖了标量、struct、vector、union 等各类字段的断言。7.1 Rust 端读取 C 写入的数据Quick Start 特别强调读取不必使用与写入相同的语言。仓库中的 samples/sample_binary.rs 正是Rust 读取 C 数据的演示——Rust 端先构造同样 schema 的缓冲区再立即读取验证// 读取根对象 let monster flatbuffers::root::Monster(buf).unwrap(); // 直接访问字段 assert_eq!(monster.hp(), 80); assert_eq!(monster.mana(), 150); // 默认值 assert_eq!(monster.name(), Some(Orc));Rust 侧通过MonsterArgs结构体以具名字段方式构造对象用builder.finish(orc, None)结束对应 C 的builder.Finish(orc)再以builder.finished_data()取得[u8]切片交给flatbuffers::root::Monster读取。这种一种 schema、多种语言的对称体验正是 FlatBuffers 生态的核心价值。8. 更进一步完整教程本文是上手速览面向所有语言的逐步详解见 tutorial.md。模式语言全解标量类型表、向量嵌套限制、enum/union 细节、attributes 清单id、required、key、hash、nested_flatbuffer等见 schema.md。schema 演进新增字段必须追加到表末尾、删除字段应使用deprecated而非直接移除、字段改名不影响二进制兼容——规则与正反示例见 evolution.md并用flatc --conform old.fbs new.fbs自动校验。编译器全部选项flatc的完整参数手册含 gRPC 相关选项见 flatc.md。运行库源码C 头文件实现位于 include/flatbuffers各语言运行库分别位于 go、rust、python、ts、swift 等目录回归测试集中在 tests如 monster_test.cpp。9. 小结至此你已经走通了 FlatBuffers 的完整链路编译flatc→ 编写.fbsschema → 生成多语言代码 → 用FlatBufferBuilder序列化 → 传输/存储 → 跨语言零解析读取。这套一次建模、随处读写的模式配合零拷贝访问与 schema 演进机制使其成为对延迟和内存占用敏感场景的可靠选择。下一步建议阅读 tutorial.md 深入每个语言的具体 API并结合仓库中的 samples 示例动手实践。【免费下载链接】flatbuffersFlatBuffers: Memory Efficient Serialization Library项目地址: https://gitcode.com/GitHub_Trending/fl/flatbuffers创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进