1.Protobuf简介
** Protobuf(Google Protocol Buffers) ** 提供一种灵活、高效、自动化的机制,用于序列化结构数据。Protobuf仅需自定义一次所需要的数据格式,然后我们就可以使用Protobuf编译器自动生成各种语言的源码,方便我们读写自定义的格式化数据。另外Protobuf的使用与平台和语言无关,可以在不破坏原数据格式的基础上,扩展新的数据。
我们可以将Protobuf与XML进行对比,但Protobuf更小、更快、更加简单。总结来说具有一下特点
- 性能好、效率高。Protobuf作用与XML、json类似,但它是二进制格式,所以性能更好。但同时因为是二进制格式,所以缺点也就是可读性差。
- 代码生成机制,易于使用。
- 解析速度快。
- 支持多种语言,例C++、C#、Go、Java、Python等。
- 向前兼容,向后兼容。
2.Protobuf安装
Mac用户可以使用brew进行安装,命令如下所示。
brew install protobuf
如需要安装特定版本,可以先进行搜索有哪些版本,命令如下所示。搜索完成之后,采用上述brew安装方法,安装特定版本即可。
brew search protobuf
安装完成之后,可以通过protoc --version查看是否安装成功。
protoc --version
libprotoc 3.6.0
另外可以通过which protoc命令查看protoc安装所在的位置。
which protoc
/usr/local/bin/protoc
3.Protobuf实例
3.1编译.proto文件
首先我们需要创建一个以**.proto结尾的文件,可以在其中定义message**来指定所需要序列化的数据格式。每一个message都是一个小的信息逻辑单元,包含一系列的name-value值对。以官网上示例,我们创建一个addressbook.proto文件,内容如下所示。
syntax = "proto2";
package tutorial;
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phones = 4;
}
message AddressBook {
repeated Person people = 1;
}
- **syntax=”proto2”**代表版本,目前支持proto2和proto3,不写默认proto2。
- package类似于C++中的namespace概念。
- message是包含了各种类型字段的聚集,相当于struct,并且可以嵌套。
- proto3版本去掉了required和optional类型,保留了repeated(数组)。其中“=1”,“=2”表示每个元素的标识号,它会用在二进制编码中对域的标识,[1,15]之内的标志符在使用时占用一个字节,[16,2047]之内的标识号则占用2个字节,所以从最优化角度考虑,可以将[1,15]使用在一些较常用或repeated的元素上。同时为了考虑将来可能会增加新的标志符,我们要事先预留一些标志符。
构建好addressbook.proto文件后,运行Protobuf编译器编译.proto文件,运行方法如下所示。其中-I表示.protoc所在的路径,--python_out表示指定生成的目标文件存在的路径,最后的参数表示要编译的.proto文件。
protoc -I=$SRC_DIR --python_out=$DST_DIR $SRC_DIR/addressbook.proto
其中SRC_DIR为目录,如果处于当前目录的话,可通过如下所示命令来编译.proto文件。
protoc -I=. --python_out=. addressbook.proto
编译完成之后会生成addressbook_pb2.py文件,里面包含序列化和反序列化等方法。
3.2序列化
import addressbook_pb2
import sys
def PromptForAddress(person):
person.id = int(raw_input("Enter person ID number: "))
person.name = raw_input("Enter name: ")
email = raw_input("Enter email address (blank for none): ")
if email != "":
person.email = email
while True:
number = raw_input("Ente