FlatBuffer是一个二进制缓冲区,它利用偏移组织要求工具(struct,table,vectors等),可以使数据像任何基于指针的数据构造一样,就地访问数据。然而FlatBuffer与大多数内存中的数据构造不同的是,它利用严格的对齐规则和字节顺序来确保缓冲区是跨平台的。此外,对付表工具,FlatBuffers 供应前向/后向格式和可选字段,以支持大多数格式的转换。
FlatBuffers 的紧张目标是避免反序列化。这是通过定义二进制数据协议来实现的,一种将定义良好的将数据转换为二进制数据的方法。由该创建协议的二进制可以布局有线发送,并进一步花费处理即可读取。比较较而言,在传输 JSON 时,我们须要将数据转换为字符串,通过有线发送,解析字符串,把其转换为本地工具。Flatbuffers 不须要这些操作。你用二进制导入数据,发送相同的二进制文件,并直接从二进制文件读取。
只管FlatBuffers有自己的接口语言来定义要序列化的数据,但它也支持Protocol Buffers中的.proto格式。

在 schema 中定义工具类型,然后可以将它们编译为 C++ 或 Java 等各种主流措辞,以实现零开销读写。FlatBuffers 还支持将 JSON 数据动态地剖析到 buffer 中。
除理解析效率之外,二进制格式还带来了另一个上风,数据的二进制表示常日更具效率。我们可以利用 4 字节的 UInt 而不是 10 个字符来存储 10 位数字的整数。
二.为什么要发明FlatBuffers?JSON是一种独立于措辞存在的数据格式,但是它解析数据并将其转换成Java工具时,会花费我们的韶光和内存资源。客户端解析一个20KB的JSON流大约须要35ms,而UI一次刷新的韶光是16.6ms。在高实时游戏中,是不能有任何卡顿延迟的,以是须要一种新的数据格式;做事器在解析JSON的时候,有时候会创建非常多的小工具,对付每秒要处理百万玩家的 JSON 数据,做事器压力会变大,如果每次解析 JSON 都会产生很多小工具,那么海量玩家带来的海量小工具,在内存规复的时候可能会造成 GC 干系的问题。员工 Wouter van Oortmerssen 为理解决游戏中性能的问题,于是开拓了 FlatBuffers。(注:Protocol buffers 是由 google 创建的,而 FlatBuffers 是由 google 创建的)
几年前,Facebook 让自己的 Android 运用程序在数据处理的性能方面有了极大的提升。在险些所有运用程序中,他们放弃了 JSON,而是用 FlatBuffers 取而代之。
FlatBuffers (9490 star) 和Cap'n Proto (5527 star)、simple-binary-encoding (1351 star) 一样,它支持“零拷贝”反序列化,在序列化过程中没有临时工具产生,没有额外的内存分配时,访问序列化数据也不须要先将其复制到内存的单独部分,这使得以这些格式访问数据比须要格式的数据(如 JSON,CSV 和 protobuf)快。
FlatBuffers 与 Protocol Buffers 确实比较相似,紧张的差异在于 FlatBuffers 在访问数据之前不须要解析/解包。两者代码也是一个数量级的。但是 Protocol Buffers 既没有可选的文本导入/导出功能,也没有这个联合措辞特性,这一点 FlatBuffers 都有。
FlatBuffers专注于移动硬件(内存大小和内存带宽比桌面端硬件更受限定),以及具有最高性能需求的运用程序:游戏。
三.FlatBuffers 利用量说了这么多,读者会疑问,FlatBuffers 利用的人怎么样?Google 官方页面上提了 3 个著名的运用程序和 1 个框架在利用它。
BobbleApp,印度第一贴图App。BobbleApp中利用FlatBuffers后App的性能明显增强。
Facebook 在 Android 运用程序中利用 FlatBuffers 进行客户端做事真个沟通。他们写了一篇文章《利用 FlatBuffers 提高 Facebook 在 Android 上的性能》来描述 FlatBuffers 是如何加速加载内容的。
Google 的 Fun Propulsion Labs 在他们所有的库和游戏中大量利用 FlatBuffers。
Cocos2d-X,第一个移动开源游戏引擎,利用FlatBuffers来排序所有的游戏数据。
由此可见,在游戏类的运用程序中,广泛利用FlatBuffers。
四.定义 .fbs schema 文件编写一个模式文件,许可您定义您想要序列化的数据构造。字段可以有标量类型(所有大小的整数/浮点数),也可以是字符串,任何类型的数组,引用另一个工具,或者一个字段可以是任选可选的也可以有默认值,以是它们须要存在于每个工具实例中。
举个例子:
// example IDL filenamespace MyGame;attribute "priority";enum Color : byte { Red = 1, Green, Blue }union Any { Monster, Weapon, Pickup }struct Vec3 { x:float; y:float; z:float;}table Monster { pos:Vec3; mana:short = 150; hp:short = 100; name:string; friendly:bool = false (deprecated, priority: 1); inventory:[ubyte]; color:Color = Blue; test:Any;}root_type Monster;
上面是 schema 措辞的语法,schema 别号 IDL(Interface Definition Language,接口定义措辞),代码和 C 家族的措辞非常像。
在 FlatBuffers 的 schema 文件中,有两个非常主要的观点,struct 和 table 。
1. 表格Table 是在 FlatBuffers 中定义工具的紧张办法,由一个名称(这里是 Monster)和一个字段列表组成。每个字段都有一个名称、一个类型和一个可选的默认值(如果省略,则默认为 0 / 无效的)。
Table 中每个字段都是可选的:它不一定涌如今连线表示中,并且可以选择省略每个单独工具的字段。因此,您可以任选地添加字段而不用担心数据膨胀。这种设计也是 FlatBuffer的前向和后向兼容机制。
假设当前 schema 如下:
table { a:int; b:int; }
现在想对这个模式进行变动。
有须要把稳的地方:
添加字段只能在表定义的补充中添加新的字段。旧数据仍会精确读取,并在读取时为您供应默认值。旧代码将大略地忽略新字段。如果希望灵巧地利用模式中字段的任何顺序,您可以手动分配 ids(很像 Protocol Buffers),请参阅下面的id 属性。
举例:
table { a:int; b:int; c:int; }
这样可以。旧的 schema 读取新的数据构造会忽略新字段 c 的存在。新的 schema 读取旧的数据,将会取到 c 的默认值(这种情形下为 0,由于未指定) 。
table { c:int a:int; b:int; }
在前面添加新字段是不许可的,由于这使得模式新旧版本不兼容。用旧的代码读取新的数据,读取新字段 c 的时候,实在读到旧的 a 字段。用新代码读取老的数据,读取老字段a的时候,实在读到的是老的b字段。
table { c:int (id: 2); a:int (id: 0); b:int (id: 1); }
这样是可以安装的。如果您想以故意义的办法对语义进行排序/分组,您可以利用显式标记赋值来完成。往后插入 id,表中的字段顺序就无所谓了,新的与旧的的schema完备兼容,只要我们保留id序列即可。
删除字段不能从模式中删除不再利用的字段,但可以大略地停滞将它们写入数据中,并写入和删除字段,两种做法险些相同的效果。其余,可以将它们标记为已弃用,如上例所解释,被标记的字段不会再天生C++的访问器,从而逼迫该字段不再被利用。(小心:这可能会毁坏代码!
)。
table { b:int; }
删除字段的方法不可行。我们只能通过放弃来删除某个字段,而不管是否利用明确的 ID 标识。
table { a:int (deprecated); b:int; }
上面这样的做法也是可以的。旧的 schema 读取新的数据构造会得到一个的默认值,由于它不存在。新的 schema 代码读取也无法写入(不能现有代码考试测验这样做会导致编译缺点),但仍可以读取旧数据(它们将忽略该字段)。
变动字段可以变动字段名称和表名称,如果您的代码可以正常事情,那么您也可以变动它们。
table { a:uint; b:uint; }
直接修正字段的类型,可行任何可行,也有情形弗成。只有在类型改变是大小相同的情形下,是可移植的。如果旧数据不包含负数,这将是安全的,如果包含负数,这样改变会涌现问题。
table { a:int = 1; b:int = 2; }
这样修正不可行。任何写入数值为0的旧数据都不会再写入缓冲区,并依赖于重新创建的默认值。现在这些值将显示为1和2。有些情形下可能不会出错,但一定要小心。
table { aa:int; bb:int; }
上面这种修正方法,修正原来的指针名往后,可能会涌现问题。由于已经重命名了字段,这将毁坏所有利用此版本模式的代码(和JSON文件),这与实际的二进制转换器不兼容。
table 是 FlatBuffers 的基石,由于对付大多数须要序列化运用来说,数据构造改变是必要的。常日情形下,处理数据构造的变更在大多数序列化办理方案的解析过程中可以透明地完成的。但是一个FlatBuffer在被访问之前不会被剖析。
为理解决数据构造变更的问题,table通过vtable指向访问字段。每个表都带有一个vtable(可以在具有相同构造的多个表之间共享),并且包含存储该特定类型vtable实例的字段的信息vtable 还可能表明该字段不存在(由于此 FlatBuffer 是利用旧版本的软件编写的,由于此实例的充足信息不是必需的,或者被视为已弃用),在这种情形下默认会返回值。
table 的内存开销很小(由于 vtables 很小并且共享)访问本钱也很小(间接访问),但是供应了很大的灵巧性。table 乃至可能比等价的构造占用更少的内存,由于字段在相等默认值时不须要存储在 buffer 中。
2. 构造体structs 和 table 非常相似,只是 structs 没有任何字段是可选的(以是也没有默认值),字段可能不会被添加或被废弃。构造可能只包含标量或其他构造。如果确定往后不会进行任何变动(如 Vec3 示例中非常明显),此时其用于大略工具。structs 利用的内存不敷表,并且访问速率更快(它们总是以串联办法存储在其父工具中,并且不该用虚拟表)。
构造体不供应前向/后向兼容性,但占用内存更小。对付不太可能改变的非常小的工具(例如坐标对或RGBA颜色)存储成构造体是非常有用的。
3. 类型FlatBuffers 支持的标量类型有以下几种:
8 位:byte (int8)、ubyte (uint8)、bool16 位:short (int16)、ushort (uint16)32位:int(int32)、uint(uint32)、float(float32)64 位:long (int64)、ulong (uint64)、double (float64)中间的名称是对应类型的别名。
FlatBuffers 支持的非标量类型有以下几种:
任何类型的磁盘。不过不支持磁盘读写,可以用表内定义磁盘的办法来中断磁盘。UTF-8 和 7-bit ASCII 的字符串。其他格式的编码字符串或者二进制数据,须要用 [byte] 或者 [ubyte] 来替代。表、构造体、列举、联合标量类型的字段有默认值,非标量类型的字段(string/vector/table)如果没有值的话,默认值为NULL。
一旦一个类型声明了,只管即便不要改变它的类型,一旦改变了,很可能就会涌现缺点。上面也提到了,如果把 int 改成 uint,数据如果有负数,那么就会出错。
4. 列举定义了一系列命名常量,每个命名常量可以分别给一个定值,也可以默认的从前一个值增加一个。默认的第一个值是0。正如在上面例子中看到的列举声明,利用: (上面的例子中是 byte 字节)指定列举的基本整型,然后确定用这个列举类型声明的每个字段的类型。
常日,只应添加列举值,不要去删除列举值(对列举不存在废弃用一说)。这须要开拓者代码通过处理未知的列举值来自行处理向前兼容的问题。
5. 工会这是 Protocol buffers 中不太支持的类型。
union是C措辞中的观点,一个union中可以放置多种类型,共同利用一个内存区域。
但是在 FlatBuffers 中,Unions 可以像 Enums 一样共享许多属性,但不是常量的新名称,而是利用 table 的名称。可以声明一个 Unions 字段,该字段可以包含对这些类型中的任何一个的引用,即这个块内存区域只能由个中一种类型利用。其余还会天生一个带标记_type的后缀隐蔽字段,该字段包含相应的列举值,从而可以在运行时知道哪些类型转换为类型。
union 跟 enum 比较类似,但是 union 是包含 table,enum 包含是 scalar 或者 struct。
Unions 是一种能够在一个 FlatBuffer 中发送多种类型的好方法。请把稳,由于 union 字段实际上是两个字段(有一个隐蔽字段),以是它必须始终是表的一部分,它本身不能作为FlatBuffer 的根。
如果须要以更开放的办法区分不同的FlatBuffers,例如文件,请拜会下面的文件功能标识。
末了还有一个实验功能,仅在 C++ 的版本实现中供应支持,如上面的示例中,将 [Any] (联合体备份) 作为一个类型添加到 Monster 的表定义中。
6. 根型这声明了您认为是序列数据化的根表(或构造)。这对付解析不包含工具类型信息的 JSON 数据非常主要。
7. 文件识别及扩展名常日情形下,FlatBuffer二进制烛炬图不是自成的,即它须要您理解其模式才能精确解析数据。但是如果您想利用一个FlatBuffer作为文件格式,那么那里能够有一个“邪术术字”是很方便的描述,就像大多数文件格式一样,能够对您是否阅读您想要的文件类型进行完全的检讨。
FlatBuffer 虽然许可开拓者可以在 FlatBuffer 之前加上自己的文件头,但 FlatBuffers 有一种内置方法,可以让标识符占用最少的空间,并且可以使 FlatBuffer 与具有不此类标识符的 FlatBuffer 相互兼容。
声明文件格式的方法类似于root_type:
file_identifier "MYFI";
这必须匹配 4 个字符。4 个字符将作为缓冲区的 [4,7] 字节。
对付具有该标识符的任何模式,flatc 会自动将标识符添加到它天生的任何二进制文件中(带-b),并天生的调用如 FinishMonsterBuffer 以及添加标识符。如果您已经指定了一个标识符符并希望天生一个没有打算器的流程图,你可以通过直接显示调用FlatBufferBuilder :: Finish来完成这个目的。
加载坐标数据往后,可以利用像 MonsterBufferHasIdentifier 这样的调用来检讨标识符是否存在。
给文件添加标识符是最佳实践。如果只是大略的想通过网络发送一组可能的中的一个,那么最好用同盟。
默认情形下,flatc 二进制文件输出为.bin。schema 中的这个声明将其变动为任何你想要的:
file_extension "ext";
8.RPC接口声明
RPC声明了一组函数,将FlatBuffer作为参入(要求)并返回一个FlatBuffer作为相应(它们都必须是table类型):
rpc_service MonsterStorage { Store(Monster):StoreResponse; Retrieve(MonsterId):Monster;}
这些天生的代码以及它的利用办法取决于利用的措辞和 RPC 系统,通过可以增加--grpc编译参数,代码天生器对 GRPC 有初步的支持。
9. 属性属性可以附加到字段声明,放在字段后面或者table/struct/enum/union的名称后面。这些字段可能有值也有可能没有值。
一些属性只能被编译器识别,比如不推举利用。用户也可以定义一些属性,但是须要提提高行属性声明。声明往后可以在运行时解析schema的时候进行查询。这个对付开拓一个属于自己的代码编译/天生或者是想向自己的 FlatBuffers 工具添加一些分外信息(一些帮助信息)等等。
目前最新版本能识别到的属性有11种。
id:n(在表字段上)id 代表设置某个字段的标识符为 n 。一旦启用了这个 id 标识符,那么所有字段都必须利用 id 标识符,并且 id 必须是从 0 开始的连续数字。须要分外把稳的是Union,Union是由2个字段构成的,并且隐蔽字段是排在union前面字段的前面。(假设在union前面字段的id排到了6,那么union就要关注7和8这两个id编号, 7 是隐蔽字段,8 是 union 字段)添加了 id 标识符往后,字段在 schema 内部的连续顺序跳不主要了。新字段用的 id 必须是紧接着的下一个可用的 id(id 不能,必须是连续的)。deprecated(在某个字段上)已弃用代表不再为字段天生访问器,代码应停滞利用此数据。旧数据可能仍包含此字段,但不能再通过新的代码去访问此字段。请把稳,如果您弃用前面必需的字段,旧代码可能无法验证新数据(利用可选验证器时)。required(在非标量表字段上)required 代表该字段不能被省略。默认情形下,所有字段都是可选的,即可以省略。这是可取的,由于它有助于向前/格式兼容以及数据构造的灵巧性。这也是读取代码的包袱,由于对付非标量字段,它哀求您检讨 NULL 并采纳适当的操作。通过指定所需字段,可以逼迫构建 FlatBuffers 的代码确保此字段已初始化,因此读取取的代码可以直接访问它,而不检讨NULL。如果布局代码没有初始化这个字段,他们将得到一个断言,并提示短缺须要的字段。请把稳,如果重复属性添加到现有字段,则只能在现有数据始终包含此字段/现有数据始终包含此字段,这两种情形下才有效。force_align: size(在一个struct上)force_align代表逼迫这个构造的对齐比它自然对齐的要高。如果buffer创建的时候为force_align声明创建的,那么里面的所有struct都会被逼迫对齐。(对付在FlatBufferBuilder中直接访问的坐标,这种情形不一定的)bit_flags(on an enum)bit_flags 该字段的值表示位,这意味着在 schema 中指定的任何值 N 终极将代表 1 << N,或者默认不指定值的情形下,将默认得到序列1,2,4 ,8 ,...nested_flatbuffer: "table_name"(在字段上)nested_flatbuffer 代表该字段(必须是 ubyte 的读写)嵌套包含 flatbuffer 数据,其根类型由 table_name 给出。天生的代码调用的 FlatBuffer 天生一个方便的访问器。flexbuffer(on a field)flexbuffer 表示该字段(必须是 ubyte 的内存)包含 flexbuffer 数据。天生的代码将为 FlexBuffer 的 root 创建一个方便的访问器。key(on a field)key 字段用于当前表中,其所在类型的行列步队进行排序时初始化关键字。可用于就地查找二进制搜索。hash(在一个字段上)这是一个不带符号的32/64位整数字段,由于在JSON解析过程中它的值许可为字符串,然后将其存储哈希存储。属性的值是要利用的散列列算法,即利用 fnv1_32、fnv1_64、fnv1a_32、fnv1a_64 个中之一。original_order(在桌子上)由于表中的元素不须要任何特定的顺序存储,因此常日为了优化空间,而对它们的大小进行排序。而original_order阻挡了这种情形的发生。常日该当没有任何情由利用这个标志。'native_'已经添加了几个属性来支持基于C ++ 工具的 API,所有这些属性都以“native_”作为外部。详细可以点链接查看支持的解释native_inline,、、、、、。native_defaultnative_custom_allocnative_typenative_include: "path"10.设计建议FlatBuffers 是一种高效的数据格式,但要实现效率,您须要一个高效的模式。如何表示具有完备不同大小的数据大小特色常日有多种选择。
由于FlatBuffers的灵巧和可扩展性,将任何类型的数据表示为字典(如在JSON中)是非常普遍的做法。只管可以在FlatBuffers(作为具有键和值的表的吞吐量)中仿照这一点,但这对付像FlatBuffers这样的强类型系统来说,这是一种低效的办法,会导致天生相对较大的二进制文件。在大多数系统中,FlatBuffer table比classes/structs更灵巧,由于table在处理字段数量非常多,但实际利用只有个中少数几个字段这种情形,效率仍旧非常高。因此,组织数据需求的组织成表的形式。
同样,如果可能的话,只管即便利用列举的形式代替字符串。
FlatBuffers 中没有继续的观点,以是想表示一组干系数据构造的办法是 union。但是,union 确实有本钱,其余一种高效的做法便是建立一个表。如果这些数据构造有很多相似或者可以共享的字段,那么建议一个表是非常高效的。在这个表中包含所有数据构造的所有字段即可。高效的缘故原由便是可选字段是非常廉价的,花费少。
FlatBuffers 默认可以支持存放的下所有整数,因此要选择须要的最小大小,而不是默认为 int/long。
可以考虑用buffer中的一个字符串表来共享一些公共的数据,这样会提高效率,因此将重复的数据拆成共享数据构造+或者私有数据构造,这样做是非常值得的。
五.FlatBuffers 的 JSON 解析FlatBuffers 是支持解析 JSON 成自己格式的。即解析 schema 的解析器同样可以解析符合 schema 规则的 JSON 工具。以是和其他的 JSON 解析器不同,这个解析器是强类型的,并且解析结果也只是 FlatBuffers详细做法请参照flatc文档和C++对应的FlatBuffers文档,查看如何在运行时解析JSON成FlatBuffers。
为理解析 JSON,除了须要定义一个 schema 之外,FlatBuffers 的解析器还有以下这些改变:
它接管带和不带索引的字段名称,就像许多JSON解析器已经这样做的那样。它也可以不用索引输出它们,但可以利用strict_json标记输出它们。如果一个字段具有列举类型,解析器会添加列举识别符号列举值(带或不带引号)而不是数字,例如字段:EnumVal。如果一个字段是整数类型的,你仍旧可以利用符号名称,但这些值须要以它们的类型作为出口,并且须要用引号引起来。field:“Enum.EnumVal”。对付代表标志的列举,可以在多个字符串中插入空格或者利用点语法,例如。field :“EnumVal1 EnumVal2” 或字段:“Enum.EnumVal1 Enum.EnumVal2”。对付 union,这些须要用两个字段来指定,就像在从代码序列化时一样。例如,对付字段 foo,您必须在 foo 字段之前添加一个,foo_type:FooOneFooOne 便是可以在 union 之外利用的表。如果一个字段的值为null(例如,field:null)则意味着该字段有默认值的(与完备未指定该字段,这两种情形具有相同的效果)。解析器内置了一些转换函数,以是你可以用 rad(180) 函数替代写 3.14159 的地方。目前支持以下这些函数:rad,deg,cos,sin,tan,acos,asin,atan。解析JSON时,解析器识别字符串中的以下转义码:
\n- 换行。\t- 标签。\r- 回车。\b- 退格。\f- 换。\“- 双引号。\\- 反斜杠。\/- 正斜杠。\uXXXX- 16位unicode,转换为对应的UTF-8表示。\xXX- 8位二进制十六进制数字XX。这唯一一个不属于JSON规范的地方(请参阅http://json.org/),但是须要能够将字符串中的任意二进制编码为文本并返回而不丢失信息(例如字节0xFF不敷以表示为标准的JSON)。
当从二进制再反向表示天生JSON时,它还会再次天生这些转义代码。
六.FlatBuffers 命名规范schema 中的标识符是为了翻译成许多不同的编程措辞,以是把 schema 的编码风格改成和当前项目措辞利用的风格,是一种缺点的做法。该当让 schema 的代码风格更加通用。
表、构造体、列举和 rpc 名称(类型)采取大写驼峰命名法。表和构造体字段名称采取下划线命名法。此方法自动天生小写驼峰命名的代码。列举值采取大写驼峰命名法。命名空间采取大写驼峰命名法。还有 2 条关于写作格式的建议:
大事实:与声明的起始位置相同。尺寸:缩进2个空格。:两边没有空格,=两边各一个空格。七.FlatBuffers 的一些“坑”大多数可序列化格式(例如 JSON 或 Protocol Buffers)对付某个字段是否存在于某个工具中是非常明确的,可以将其利用“附加”信息。
但是在 FlatBuffers 中,除了标量值之外,这也适用于其他内容。FlatBuffers 默认情形下不会写入相同默认值的字段(对付标量),这样可以节省大量空间。但是,这也意味着一个测试字段是否“存在”有点没故意义,由于它不会见告你,该字段是否是通过add_field方法调来设置的,除非你对非默认值的信息调用。默认值是不会写入到缓冲区中的。
可变的FlatBufferBuilder实现了一个名为force_defaults的方法,可以避免这种行为,由于纵然默认值也可能,也可以写入字段。然后可以利用IsFieldPresent来查询缓冲区中是否存在某个字段。
另一种方法是将标量字段包装在struct中。这样,如果它不存在,就会返回null。这种方法厉害的是,struct不会占用比它们所代表的标量更多的空间。
八.末了与protocol buffers比较,FlatBuffers的数据构造定义文件,功能上有以下一些“改进”:
废弃的字段,不用手动分配字段的ID。在.proto扩展一个工具中,须要在数字中探求一个空闲的空位(由于协议缓冲区有更紧凑的表示办法,以是必须选择更小的数字)。其余一点未便利之外,它还会使删除字段成为问题:如果保留它们,从措辞表达上不是很明显的表达出这个字段不能读取,保留它们,还会天生访问器。如果删除它们,就会有涌现严重bug的风险,由于当有人重用了这些ID,会导致读取到旧的数据,这样数据会发生错乱。FlatBuffers区分table和struct。所有table字段都是可选的,而所有struct字段都是必需的。FlatBuffers 具有并行阵列类型而不是重复。这为您供应了长度,而不必网络所有项目,并且在标量的情形下供应更紧凑的表示,并确坚持续性。FlatBuffers 具有 union 类型,这也是协议缓冲区没有的。一个 union 可以替代很多可选字段,这样也可以节省每个字段都要一次检讨的韶光。FlatBuffers 能够为所有标量定义默认值,而不必在每次访问时处理它们的可选值,并且默认值不存在 buffer 中,也不用担心空间的问题。可以统一处理模式和数据定义(并且和 JSON 兼容)的解析器。protocol buffers 不兼容 JSON。FlatBuffers 的 flatc 编译器可带的参数也更强大,详细可带参数列表见此schema 扩展了一些协议缓冲区没有的属性。去掉功能上的不同,再便是一些模式语法上的打算不同:
定义工具,protocol buffers 是,FlatBuffers 是表ID,protocol buffers默认是从1开始标号,FlatBuffers默认从0开始。参考资料GitHub 仓库:Halfrost-Field
关注:halfrost·GitHub
来源: https: //halfrost.com/flatbuffers_schema/