我们在使用protobuf之前首先要了解protobuf,那么什么是protobuf呢?
官方的解释是:
protocol buffers 是一种与语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等。
Protocol Buffers 是一种灵活,高效,自动化机制的结构数据序列化方法-可类比 XML,但是比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单。
你可以定义数据的结构,然后使用特殊生成的源代码轻松的在各种数据流中使用各种语言进行编写和读取结构数据。你甚至可以更新数据结构,而不破坏由旧数据结构编译的已部署程序。
简单的来说,ProtoBuf
和json
、xml
一样是一种结构化的数据格式,用于数据通信的传输及数据的存储。但ProtoBuf
相比json
和xml
来说具有以下的优点:
缺点:
在Protobuf中,.proto
文件相当于确定数据协议,数据结构中存在哪些数据,数据类型是怎么样的。先来看一个简单的.proto
文件的数据结构,然后再来详细了解一下protobuf语法
syntax = "proto3";
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
}
proto3
语法:如果您不这样做,protobuf 编译器将假定您正在使用proto2。这必须是文件的第一个非空的非注释行。SearchRequest
消息定义了三个字段(名称/值对),每个字段都有一个名称和类型,及唯一的数字标识符。protobuf2中.proto
文件中的数据结构由以下几部分组成:
Potobuf3与Protobuf2不同的地方:
1、字段规则:
2、取消了设置默认值:
3、支持的数据类型有:
double、float、int32、int64、uint32、uint64、sint32、sint64、fixed32、fixed64、sfixed32、sfixed64、bool、string、bytes
4、分配标识符:
正如上述文件格式,在消息定义中,每个字段都有唯一的一个数字标识符。这些标识符是用来在消息的二进制格式中识别各个字段的,一旦开始使用就不能够再改变。
注意:[1,15]之内的标识号在编码的时候会占用一个字节。[16,2047]之内的标识号则占用2个字节。所以应该为那些频繁出现的消息元素保留 [1,15]之内的标识号。切记:要为将来有可能添加的、频繁出现的标识号预留一些标识号。
最小的标识号可以从1开始,最大到2^29 - 1, or 536,870,911。不可以使用其中的[19000-19999]的标识号, Protobuf协议实现中对这些进行了预留。如果非要在.proto文件中使用这些预留标识号,编译时就会报错。
1. 首先下载平台对应的proto编译器,根据平台下载对应版本:
https://github.com/google/protobuf/releases
windows平台可以下win64。
然后将压缩包解压,将压缩包中bin目录下的proto.exe文件放到项目目录下,用于将来编译.proto
文件。
在该目录下执行:protoc.exe --version判断是否可用
然后执行:pip install protobuf 安装protobuf模块
2. 在项目目录下创建test.proto
文件,定义数据结构
syntax = "proto3"; // 指定protobuf语法版本
package Protobuf_test; // 包名
message AddressBook {
repeated Person people = 1;
}
message Person {
string name = 1;
int32 id = 2;
string email = 3;
float money = 4;
bool work_status = 5;
repeated PhoneNumber phones = 6;
MyMessage maps = 7;
}
message PhoneNumber {
string number = 1;
PhoneType type = 2;
}
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message MyMessage {
map<int32, int32> mapfield = 1;
}
3. 使用proto.exe
编译.proto
文件,生成一个对应的.py
的文件
在项目目录下执行:proto.exe --python_out = ./ test.proto
4. 接下来就可以编写python程序进行序列化和反序列化了
import test_pb2
address_book = test_pb2.AddressBook()
person = address_book.people.add()
person.id = 1
person.name = 'lichungang'
person.email = '[email protected]'
person.money = 1
person.work_status = True
phone_number = person.phones.add()
phone_number.number = "123456"
phone_number.type = test_pb2.MOBILE
maps = person.maps # maps类型是singular,不是repeated类型无法使用add()
maps.mapfield[1] = 1
maps.mapfield[2] = 2
# 序列化
serialize_to_string = address_book.SerializeToString()
print(serialize_to_string, type(serialize_to_string))
# 反序列化
address_book.ParseFromString(serialize_to_string)
for person in address_book.people:
print("p_id:{},p_name:{},p_email:{},p_money:{},p_workstatu:{}"
.format(person.id, person.name, person.email, person.money, person.work_status))
for phone_number in person.phones:
print(phone_number.number, phone_number.type)
for key in person.maps.mapfield:
print(key, person.maps.mapfield[key])
结果:
b'\n<\n\nlichungang\x10\x01\x1a\[email protected]%\x00\x00\x80?(\x012\x08\n\x06123456:\x0c\n\x04\x08\x01\x10\x01\n\x04\x08\x02\x10\x02' <class 'bytes'>
p_id:1,p_name:lichungang,p_email:xxxxx@163.com,p_money:1.0,p_workstatu:True
123456 0
1 1
2 2
参考:
https://www.cnblogs.com/sanshengshui/p/9739521.html
https://blog.csdn.net/caisini_vc/article/details/5599468