尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

FlatBuffers C++ 如何在运行时解析 schema 与 JSON 文本生成二进制 buffer?

FlatBuffers C++ 如何在运行时解析 schema 与 JSON 文本生成二进制 buffer? FlatBuffers C 如何在运行时解析 schema 与 JSON 文本生成二进制 buffer【免费下载链接】flatbuffersFlatBuffers: Memory Efficient Serialization Library项目地址: https://gitcode.com/GitHub_Trending/fl/flatbuffers你手上已经有一个 FlatBuffers schema.fbs文件和一批现成的 JSON 数据希望在 C 程序运行时把 JSON 直接解析成 FlatBuffers 二进制 buffer而不是要求用户或工具链在构建期做一步转换。FlatBuffers 的 C 实现提供了flatbuffers::Parser来完成这件事先解析 schema 建立类型定义再解析 JSON解析结果直接存放在 parser 内部的FlatBufferBuilder里取出后就是一份可被生成代码如GetMonster()读取的二进制 buffer。官方文档明确说明这种“程序直接加载文本”的能力目前只对 C 提供Java 通过 JNI 间接使用所以本文的操作路径适用于 C 项目。准备条件引入 FlatBuffers 源码。对 C 来说常规读/写 FlatBuffer 只需要单个头文件include/flatbuffers/flatbuffers.hbuilding.md 将其描述为通常没有需要编译的运行时库。但要在运行时加载 schema 和/或解析文本生成二进制 buffer必须额外编译/链接src/idl_parser.cpp如果还想把二进制转回文本则再链接src/idl_gen_text.cpp并在代码中 include flatbuffers/idl.h。CMake 项目的接入方式。如果主工程已经用 CMake推荐把 FlatBuffers 源码通过add_subdirectory()直接并入构建这样两边共用同一套编译/链接设置building.md 给出的做法# Add FlatBuffers directly to our build. This defines the flatbuffers target. add_subdirectory(${FLATBUFFERS_SRC_DIR} ${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-build EXCLUDE_FROM_ALL) # The flatbuffers target carry header search path automatically if CMake 2.8.11. target_link_libraries(own_project_target PRIVATE flatbuffers)${FLATBUFFERS_SRC_DIR}替换为你本机 FlatBuffers 源码所在目录。生成用于读取 buffer 的 C 头文件可选但验证时需要。如果你希望解析出 buffer 后用类型化访问器如GetMonster()、monster-hp()检查内容需要先用flatc --cpp schema.fbs生成 C 头文件flatc可用 CMake 构建cmake -G Unix Makefiles后make flatc。主路径用 Parser 依次解析 schema 与 JSON仓库自带一份完整可编译的示例 samples/sample_text.cppCMake 构建中它和库源码一起组成FlatBuffers_Sample_Text_SRCS目标见 CMakeLists.txt其核心流程如下路径均相对仓库根目录#include flatbuffers/idl.h #include flatbuffers/util.h #include monster_generated.h // Already includes flatbuffers/flatbuffers.h. using namespace MyGame::Sample; // This is an example of parsing text straight into a buffer and then // generating flatbuffer (JSON) text from the buffer. int main(int /*argc*/, const char* /*argv*/[]) { // load FlatBuffer schema (.fbs) and JSON from disk std::string schemafile; std::string jsonfile; bool ok flatbuffers::LoadFile(samples/monster.fbs, false, schemafile) flatbuffers::LoadFile(samples/monsterdata.json, false, jsonfile); if (!ok) { printf(couldnt load files!\n); return 1; } // parse schema first, so we can use it to parse the data after flatbuffers::Parser parser; const char* include_directories[] {samples, nullptr}; ok parser.Parse(schemafile.c_str(), include_directories) parser.Parse(jsonfile.c_str(), include_directories); assert(ok); // here, parser.builder_ contains a binary buffer that is the parsed data. // to ensure it is correct, we now generate text back from the binary, // and compare the two: std::string jsongen; if (GenText(parser, parser.builder_.GetBufferPointer(), jsongen)) { printf(Couldnt serialize parsed data to JSON!\n); return 1; } if (jsongen ! jsonfile) { printf(%s----------------\n%s, jsongen.c_str(), jsonfile.c_str()); } printf(The FlatBuffer has been parsed from JSON successfully.\n); }以上为仓库示例原文运行目录为仓库根目录。把其中samples/monster.fbs与samples/monsterdata.json换成你自己的 schema 和 JSON 文件即可include_directories的写法对应 idl.h 中Parse的签名include_paths必须以nullptr结尾不传时 include 语句会从当前目录解析。示例体现了几个关键操作约定均出自 cpp.md 的 Text schema parsing 一节先解析 schema再解析 JSON。同一Parser对象可以顺序解析多个文本文件后面的文件可以引用前面文件的定义典型顺序就是先 schema填充定义再一个或多个 JSON 文件。文本读入内存后交给Parse。文档推荐使用 flatbuffers/util.h 的LoadFile()便利函数读取文件内容。出错判断。若有任何解析错误Parse返回falseParser::error_包含带行号的可读错误信息应把它呈现给数据文件的创建者。取二进制 buffer。每解析完一个 JSON 文件后parser 的 builder 成员就是该文件的二进制版本。需要说明一处文档与源码的出入cpp.md 正文称该成员为Parser::fbb而当前源码 idl.h 声明为FlatBufferBuilder builder_示例代码使用的也是parser.builder_。以你实际编译的源码为准。取出指针后即可按普通 FlatBuffer 二进制读取// schema 与 JSON 解析成功之后 const void* buf parser.builder_.GetBufferPointer(); auto monster GetMonster(static_castconst char*(buf)); std::cout hp : monster-hp() std::endl;第二个代码块是把文档描述的两种方式组合cpp.md 说明解析后的 buffer“可按上文方式访问”而上文读取示例即用GetMonster(data)配合生成头文件中的字段访问器。验证结果示例程序给出了一条自带校验的路径解析完成后调用GenText()从二进制 buffer 重新生成 JSON 文本并与原始输入 JSON 对比流程正常时终端输出The FlatBuffer has been parsed from JSON successfully.这是示例自身的成功提示不是固定格式断言。你也可以像上文代码块那样用访问器抽查字段——cpp.md 中读取monsterdata_test.mon的示例展示了字段访问器输出hp为80、mana取默认值150、name为MyMonster均为文档示例值。如果该 buffer 后续要当作不可信数据来源处理或想在 debug 模式下多一层保险可以在访问前用 verifier 检查cpp.md Access of untrusted buffers 一节Verifier verifier(buf, len); bool ok VerifyMonsterBuffer(verifier);ok为 true 时 buffer 才能安全读取。替代路径构建期用 flatc 转换如果数据在发布时已经固定、不需要程序运行时解析官方推荐的更省事路径是让flatc直接做转换cpp.md 称之为 “preferred path”不引入任何新代码随程序分发二进制数据flatc -b myschema.fbs mydata.json生成mydata_wire.bin之后按普通 FlatBuffer 二进制文件加载即可。缺点是需要用户/开发者多做这一步可自动化。两条路径按需求二选一数据固定选构建期转换数据动态或要随文本一起分发才用运行时Parser。限制与注意点语言范围运行时文本解析当前仅 C 可用Java 通过 JNI其他语言的运行时没有此能力。嵌套深度schema/JSON 解析器是递归实现内置递归深度限制默认64。嵌套层数很深的 JSON 会触顶可通过编译定义FLATBUFFERS_MAX_PARSING_DEPTH覆盖CMake 项目在add_subdirectory()之前加set(FLATBUFFERS_MAX_PARSING_DEPTH 16)之类指令building.md 有对应说明。C-locale 依赖内部解析依赖 C-locale 的strtod()/strtof()等函数浮点小数分隔符必须是.使用,等其他分隔符的 locale 会破坏解析。库会在配置/编译期探测 locale 无关函数并定义FLATBUFFERS_LOCALE_INDEPENDENT。编译器选项库假设符合 IEEE-754开启fast-math或/fp:fast时 schema 与 JSON 解析可能失败。JSON 格式接受的 JSON 格式见 schema.mdJSON 数据的演进兼容性与二进制格式遵循同样的规则。拿到 buffer 之后后续读取、遍历的方式与普通 FlatBuffers 二进制完全一致cpp.md 中std::ifstream读文件再GetMonster(data)的示例可以回到该章节继续对照使用。【免费下载链接】flatbuffersFlatBuffers: Memory Efficient Serialization Library项目地址: https://gitcode.com/GitHub_Trending/fl/flatbuffers创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表