@[tools|flatbuffers|opensource]

概述###

Google在今年6月份发布了跨平台序列化工具FlatBuffers,提供了C++/Java/Go/C#接口支持,这是一个注重性能和资源使用的序列化类库。相较于Protocol Buffers,其更适用于移动设备,FlatBuffers提供更高的性能以及更低的资源需求。

特点####

  • 不需要打包/解包。它的结构化数据都以二进制形式保存,不需要数据解析过程,数据也可以方便传递
  • 省内存、性能好
  • 强类型系统,在编译阶段就能预防一些bug的产生
  • 跨平台(C++11/Java/Go/C#)

FlatBuffers和Protocol Buffers以及Json的比较:####

  • FlatBuffers的功能和Protocol Buffers很像,他们的最大不同点是在使用具体的数据之前,FlatBuffers不需要解析/解包的过程。同时,在工程中使用时,FlatBuffers的引用比Protocol Buffers方便很多,只需要包含两三个头文件即可
  • JSON作为数据交换格式,被广泛用户各种动态语言之间(当然也包括静态语言)。它的优点是易于理解(可读性好),同时它的最大的缺点那就是解析时的性能问题了。而且因为它的动态类型特点,你的代码可能还需要多写好多类型、数据检查逻辑。

FlatBuffers的使用步骤####

  • 编写一个用来定义数据结构的schema(IDL,接口定义)文件,如下所示:
    //flatbuffers test struct

    namespace Jason.Flat.Test;

    enum Color : byte { Red = 1, Green, Blue }

    union Any { TextureData, Texture }

    table TestAppend {
test_num:int;
test_num2:int;
} table TextureData {
image_size:int (id:0);
image_data:[ubyte] (id:1);
image_test:short(id:3);
test_num2:int(id:2);
} table Texture {
num_textures:short;
textures:[TextureData];
num_test:short = 30;
num_test1:short (deprecated);
num_test2:short;
test_append:TestAppend;
} root_type Texture;

将上述代码保存为TestFlat.fbs文件之后,即可用flatc来编译了

  • 使用FlatBuffer编译器flatc生成数据结构源代码(C++头文件或者Java类)
    登录GitHub,下载所需版本的源码及工程文件,在build目录下有VS2010的工程文件(当然,你也可以选择利用CMake自己本地创建工程),打开配置好flatc工程的传入参数,如下:
    -c -o ./ ./TestFlat.fbs
    运行flatc工程,即可在当前工程目录下生成TestFlat_generated.h头文件,这个头文件中包含了我们所需的所有结构体、枚举类型等以及相应的存取方法和验证方法
  1. 使用FlatBufferBuilder类创建flat的二进制buffer
    以下代码展示了如何利用FlatBufferBuilder创建相应buffer:
    //read serialized buffer
flatbuffers::FlatBufferBuilder builder_data; int test_append = 300;
auto name_test = builder_data.CreateString("TestAppend");
auto testApp = CreateTestAppend(builder_data, test_append, test_append); int image_size = 12;
unsigned char inv_data[] = { 11, 2, 4, 2, 10, 3, 5 ,7, 10, 39, 45, 23 };
auto name = builder_data.CreateString("TextureData");
auto image_data = builder_data.CreateVector(inv_data, image_size); int image_test = 900;
auto texture_data = CreateTextureData(builder_data, image_size, image_data, image_test, image_test); //flatbuffers::FlatBufferBuilder builder_tex;
int texture_num = 1; auto name_tex = builder_data.CreateString("Texture"); vector<flatbuffers::Offset<TextureData>> tex_vec;
tex_vec.push_back(texture_data);
auto tex_data = builder_data.CreateVector(tex_vec); int num_text = 100, num_text2 = 200, num_text3 = 300;
auto texture = CreateTexture(builder_data, texture_num, tex_data, num_text, num_text2, testApp);
builder_data.Finish(texture);

要使上述正确运行,除了引用C++基本库之外,需在文件头部添加以下代码:

#include "flatbuffers/flatbuffers.h"
#include "idl.h"
#include "util.h"
#include "TestFlat_generated.h"
using namespace Jason::Flat::Test;

上述代码的编写中规中矩,其中CreateString和CreateVector都是FlatBufferBuilder类的成员函数,分别用于创建适用于FlatBuffer内存结构的字符串数据以及向量数据。其余的方法,如CreateTextureData、CreateTexture均是由flatc根据IDL文件(TestFlat.fbs)自动生成的头文件中用于创建相应结构体的函数。最后一句builder_data.Finish(texture)用于优化对齐写入builder_data的内存结构。

  1. 保存buffer到本地或者直接通过网络发送
    保存buffer到本地的代码,如下:
std::cout << builder_data.GetSize() << std::endl;
flatbuffers::SaveFile("texture.bin", reinterpret_cast<char *>(builder_data.GetBufferPointer()), builder_data.GetSize(), true);

将数据保存到名为texture.bin的二进制文件中,其中通过builder_data.GetBufferPointer()获取内存指针,builder_data.GetSize()获取内存大小,最后一个参数用于制定是否生成二进制文件。

  1. 接收并buffer并读取数据内容
    读取二进制文件的代码如下:
    string binaryfile;
bool ok = flatbuffers::LoadFile("texture.bin", false, &binaryfile); flatbuffers::Verifier tex_verify(builderOut.GetBufferPointer(), builderOut.GetSize());
bool verify_flag = VerifyTextureBuffer(tex_verify); flatbuffers::FlatBufferBuilder builderOut;
TextureBuilder* texBuilder = new TextureBuilder(builderOut);
builderOut.PushBytes(reinterpret_cast<unsigned char*>(const_cast<char *>(binaryfile.c_str())), binaryfile.size());
std::cout << builderOut.GetSize() << std::endl; auto model = GetTexture(builderOut.GetBufferPointer()); int outNum = model->num_textures();
const flatbuffers::Vector<flatbuffers::Offset<TextureData>>* outTex = model->textures();
TextureData* outTexData = (TextureData *)outTex->Get(0);
int outSize = outTexData->image_size();
const flatbuffers::Vector<unsigned char>* outData = outTexData->image_data();
int x = outData->Get(5);
int len = outData->Length();
delete texBuilder;

上述代码中VerifyTextureBuffer用于验证读取的内存是否为FlatBuffers的内存块,是则返回true,不是则返回false。通过GetTexture获取指针之后,结构体中的变量均可以通过相应方法(各方法名请查看自动生成的头文件)获取。

总结####

利用FlatBuffers来进行数据保存及传输的优点显而易见,它利用自身特殊的编码格式,能一定程度上减少内存的占用,优化读取的性能。更重要的是,对于数据结构的向前向后兼容提供了很好的扩展性,方便又高效:

  • 要想让数据结构具有可扩展性,需将数据结构定义为table,它是数据扩展的基础,FlatBuffers中的struct类型不支持扩展
  • 如果想在后续的版本中删除数据结构中的某些字段,只要在将要删除的字段后面添加(deprecated)即可,当然需要保证删除的字段在之前版本的程序中不会引起程序崩溃(该删掉的字段在上一版本的程序中获取到的会是个空指针或空值,只需保证程序在获取到空值或空指针之后不会出现异常即可)
  • 如果想在后续版本中向数据结构中添加某些字段,需添加到table中最后一个字段的后面,若是想table中随意位置添加字段,需如上面TextureData 的定义,给每个字段指明添加id:n(n从0开始)

目前FlatBuffers还不是很完善,碰到问题可以到FlatBuffers Issues Tracker去提交或则寻找答案。

参考链接
FlatBuffers Documentation
github repository
Google FlatBuffers 跨平台序列化工具
FlatBuffers与protobuf性能比较


作者:drybeans
链接:https://www.jianshu.com/p/6eb04a149cd8
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

FlatBuffers使用简介的更多相关文章

  1. 移动端目标识别(1)——使用TensorFlow Lite将tensorflow模型部署到移动端(ssd)之TensorFlow Lite简介

    平时工作就是做深度学习,但是深度学习没有落地就是比较虚,目前在移动端或嵌入式端应用的比较实际,也了解到目前主要有 caffe2,腾讯ncnn,tensorflow,因为工作用tensorflow比较多 ...

  2. Flatbuffers学习

    flatbuffers简介 FlatBuffers 是一个(二进制 buffer)序列化开源库,由 Google 开源现在它支持C++, C#, C, Go, Java, Kotlin, JavaSc ...

  3. ASP.NET Core 1.1 简介

    ASP.NET Core 1.1 于2016年11月16日发布.这个版本包括许多伟大的新功能以及许多错误修复和一般的增强.这个版本包含了多个新的中间件组件.针对Windows的WebListener服 ...

  4. MVVM模式和在WPF中的实现(一)MVVM模式简介

    MVVM模式解析和在WPF中的实现(一) MVVM模式简介 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 MVVM模式解析和在 ...

  5. Cassandra简介

    在前面的一篇文章<图形数据库Neo4J简介>中,我们介绍了一种非常流行的图形数据库Neo4J的使用方法.而在本文中,我们将对另外一种类型的NoSQL数据库——Cassandra进行简单地介 ...

  6. REST简介

    一说到REST,我想大家的第一反应就是“啊,就是那种前后台通信方式.”但是在要求详细讲述它所提出的各个约束,以及如何开始搭建REST服务时,却很少有人能够清晰地说出它到底是什么,需要遵守什么样的准则. ...

  7. Microservice架构模式简介

    在2014年,Sam Newman,Martin Fowler在ThoughtWorks的一位同事,出版了一本新书<Building Microservices>.该书描述了如何按照Mic ...

  8. const,static,extern 简介

    const,static,extern 简介 一.const与宏的区别: const简介:之前常用的字符串常量,一般是抽成宏,但是苹果不推荐我们抽成宏,推荐我们使用const常量. 执行时刻:宏是预编 ...

  9. HTTPS简介

    一.简单总结 1.HTTPS概念总结 HTTPS 就是对HTTP进行了TLS或SSL加密. 应用层的HTTP协议通过传输层的TCP协议来传输,HTTPS 在 HTTP和 TCP中间加了一层TLS/SS ...

随机推荐

  1. 谈Swift中的访问控制

    访问控制(Access Control) 访问控制可以限定其他源文件或模块中的代码对你的代码的访问级别.这个特性可以让我们隐藏代码的一些实现细节,并且可以指定一些代码和访问和使用的优先接口. 你可以明 ...

  2. iOS开发过程中常见错误问题及解决方案

    错误原因:ld: x duplicate symbol for architecture x86_64 clang: error: linker command failed with exit co ...

  3. 2015年蓝桥杯C/C++ B组题目题解

    1. 输入一个字符串,求它包含多少个单词.单词间以一个或者多个空格分开. 第一个单词前,最后一个单词后也可能有0到多个空格.比如:" abc xyz" 包含两个单词,"a ...

  4. tomcat 日志禁用

    1.禁用catalina.out日志通过修改catalina.sh配置可以控制tomcat不生成该文件只要将if [ -z "$CATALINA_OUT" ] ; then CAT ...

  5. 关于Json如何转换成对象及获值问题!

    var result = eval('('+result+')'); result为Json 转换成var result对象,可以 if(result.success){ window.locatio ...

  6. 51nod 1060 最复杂的数 反素数

    1060 最复杂的数 基准时间限制:1 秒 空间限制:131072 KB 把一个数的约数个数定义为该数的复杂程度,给出一个n,求1-n中复杂程度最高的那个数. 例如:12的约数为:1 2 3 4 6 ...

  7. bzoj 1087 [SCOI2005]互不侵犯King 状态压缩dp

    1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec  Memory Limit: 162 MB[Submit][Status][Discuss] Descripti ...

  8. iOS 使用宏定义函数和代码块

    iOS使用宏定义函数和代码块 今天在开发过程中碰到一个问题:就是父类中要向外发送通知,然后子类中或者其他类中来接收它.当然一般是把它写到类方法中去,但是有个问题,就是如果调用的类不是它的子类,就不能直 ...

  9. 查看后台PHP进程(非PHP-FPM)

    ps -ef | grep php | grep -v php-fpm

  10. The import java.util cannot be resolved

    原因:项目buildpath不对 解决方案: 右键项目-------build path--------configuration build path 的选择libraries找到JRE(这个时候你 ...