Protocol Buffers
使用描述型文件.proto 生成多种语言版本的控制接口代码。
优点
- 更紧凑的数据存储
- 解析速度快
- 可用于多种语言
- 自动生成功能丰富的控制类
缺点
- 大数据。超过几 mb 的数据,因为序列化拷贝时会产生数据的数个副本,消耗大量内存
- 需要比较。数据序列化后可能产生不同的序列化结果,在完全解析前无法比较
- 不会被压缩。特定的压缩算法往往效果比 protobuf 更好
- 大型多维浮点数组,在空间和速度上都比不过专门处理这种类型的工具
- 不适合非面向对象的语言
- 不是自解释的语言,需要访问.proto 文件
- 不是任何组织的正式标准,不适合用在有法律或者其他要求的环境
工作流程
- 创建.proto 文件,并定义数据结构
- 使用 protoc 编译器生成代码
- 将 protobuf 的代码和项目代码一起编译
- 使用 protobuf 类在不同语言间进行数据的序列化和反序列化
语法
package
: 包声明,防止命名冲突,在 C++ 中会作为生成类的 namespacemessage
: 信息数据结构,支持普通数据结构,也支持其他message
类型的结构,可以嵌套optional
: 可缺省的field
, 若没有,将会使用默认值,通过[default = xxx]
指定,若无指定,则指定系统默认值- numeric: 0
- bytes: empty bytes
- strings: ''
- bools: false
- enums: 第一个被定义的枚举值,必须为 0
- 嵌合类型:
field
不会被 set?,具体值根据语言不同而不同
repeated
: 可以重复任意次 (包括 0) 的field
, 重复项的顺序会被保留,可视为动态数组required
: 必须提供的field
, 否则信息会被视为uninitialized
. 在debug
模式中编译,线性化一个未初始化的量会触发断言。在优化模式下编译,则不会被检查,信息会被直接写入,但是解析一个uninitialized
的信息永远会失败,会返回false
. 其他同optional
- 使用 required 会造成向后兼容问题,最好不用,在 proto3 中已被删除
map
(proto 3): 键值对field
, 包含repeated
enum
: 枚举,可以在预先确定的类型中选一个,field number 从 0 开始=1, =2 (field number)
: 在每个field
中唯一的数字,用于数据线性化,数字 1-15 在序列 化时,比别的数字需要的空间少一字节,可以通过给常用的数据安排 1-15 的序列,优化空间使用。每个repeated
类型的领域需要重编码field number
, 所以尤其适合这种优化.?
注意
- 在删除时
field
时,需要使用reserved
保留 field number 和 field name 以防止复用,因为在线性化时会使用到 field number,如果使用相同的 field number,不同的定义解析,会造成错误。 - 可通过复用信息对象来节省内存
编码格式
Varint
Varint 编码是一种可变长的编码方式,值越小的数字可以用越少的字节表示
field-number
: message 中最后一列的数字wire-type
: 编码类型,varint 的编码类型为 0msb
: most significant bit, 每个字节的最高位- Tag 信息: 主要储存
field-number
和wire-type
- Data 信息: 编码后的序列
Varint 编码序列 = Tag 信息 + Data 信息