Skip to content

ProtoBuffer

Proto Buffer

它是一个Google推出的以二进制形式序列化数据的库。它包含了数据体的声明和目标语言对应数据体的数据类代码、序列化、反序列化代码生成。数据格式的声明需要使用*.proto文件,并给出了一份对应的格式声明规范。

和众多序列化反序列化手段相似,要么牺牲可读性提高存储效率,要么提高可读性降低存储效率。与JSON/XML相比,它属于前者。在存储效率上远高于JSON。尽管,据我所知,有的格式更进一步,在二进制序列化数组上再次压缩,可以得到更小的体积。

除了存储效率外,它的另一个优点在于,平台无关的proto数据体定义。这对于一份数据体需要在多端消费的场景下有所收益。尤其和传统的在特定平台对JSON反序列化得到数据类相比,此方式可以统一各平台的反序列化过程,去除样化的字段解析过程,而让精力关注于数据体的描述上。

而目前来看,Proto Buffer采取的特定平台自动编译,是对特定平台开发所使用的特定语言情景下的妥协。即,如果各端若有统一的语言,则可以不必出现针对多语言的数据体编译工具。在这个角度上讲,Kotlin和Javascript是潜在的替代者。在部分场景下,只需要用它们之一的语言来完成数据体声明和解析,便可在多平台上消费。

数据体定义

Protobuf不仅引入了描述数据的一套统一的字段类型(主要包含数字类型、字符串、布尔、列表、map等),此外还提供了import,package,option作为数据体模块间的复用、解耦,以及对平台特性的拓展。

但对于手动指定编号,个人觉得较为麻烦。应当将此作为建议的方式但非必须的,自动根据字段名去生成编号、并考虑对应的保留字段措施应该也会可行。

序列化与反序列化

ProtoBuffer的序列化/反序列化相对简单。写入数据时,对每个基本类型都先写入tag,再写入具体信息。对于变长类型的字段,在写入tag后,会先写入长度。对于定长类型的字段,读取tag后即可确认后续数据的字节范围。对于对象类型,则递归进行此过程。

这个和常见的序列化反序列化手段没有太多区别。类似Parcel,均有工具生成writeXxx, readXxx的代码。尽管Protobuf的差异在于,它不依赖字节的顺序,从而可以在新旧版本中均能被合理解析,解析时只关注tag来确认所读取的字段。而parcel严格依赖于顺序,自身并不具备版本兼容的能力。

而二进制的这种先类型、再长度、再数据的格式,也比较常规,没什么其他所说的。

适用场景

除了前面所说的统一数据体描述以外,它对嵌入式场景、蓝牙传输数据等偏底层方向时,有比较好的使用诉求。

拓展阅读