Protocol Buffer Serialization 指的是使用 Protocol Buffer 进行数据序列化的过程。在这个过程中,结构化的数据被转换成 Protocol Buffer 的二进制格式、文本 json 格式,以便于存储、传输或者在不同的系统之间进行交换。
Protocol Buffer Serialization 的优点包括序列化后数据的紧凑性、高效性以及跨语言、跨平台的兼容性。这使得它成为许多分布式系统和网络通信中的首选序列化方法之一。
项目:https://github.com/protocolbuffers/protobuf
文档:https://protobuf.dev/
1. Proto 编译
从 https://github.com/protocolbuffers/protobuf/releases 或者从右侧的网盘下载 protobuf 编译器,并将 bin 目录配置 PATH 环境变量中。
安装 Python protobuf 第三方库:
pip install protobuf==5.27.1 -i https://pypi.tuna.tsinghua.edu.cn/simple/
注意:protobuf 的编译器版本要和 python protobuf 库的版本要保持一致。我们 protoc 使用的是 27.1 版本,对应的 protobuf 的 5.27.1 版本。
syntax = "proto3"; enum Week { Mon = 0; Tue = 1; Wed = 2; Thu = 3; Fri = 4; Sat = 5; Sun = 6; } message Custom { int32 attr1 = 1; int32 attr2 = 2; } message Demo { string name = 1; int32 numb = 2; Week week = 3; repeated int32 rept = 4; map<string, int32> mpsi = 5; Custom cust = 6; }
当编写完数据定义相关的 .proto 文件,我们还需要使用 protobuf 编译器来生成对应语言的数据类文件。
Document:https://protobuf.dev/programming-guides/proto3/#generating
对于 Python,每个 proto 文件会生成两种不同的文件:
- foo_pb2.py: 实际使用的模块文件
- foo_pb2.pyi:编辑器可以根据
.pyi
文件提示可用的方法和属性
需要注意的是,默认 pyi 文件不会自动生成需要指定,需要指定 --python_out=pyi_out:输出路径
。
# 不生成 pyi 文件 protoc *.proto --python_out=. # 生成 pyi 文件 protoc *.proto --python_out=pyi_out:.
2. 对象序列化
在 Protobuf 中 SerializeToString 函数可以将 Python 数据对象序列化为二进制数据(字节类型),ParseFromString 函数可用以将二进制数据反序列化为 Python 数据对象。
from demo_pb2 import Demo, Week, Custom from google.protobuf import json_format # 1. 对象操作 def test01(): demo = Demo() # 1. 基本类型 demo.name = "张三" demo.numb = 200 demo.week = Week.Thu # 2. 自定义类型 demo.cust.attr1 = 100 demo.cust.attr2 = 200 # 3. repeated 类型 demo.rept.append(10) demo.rept.append(20) demo.rept.insert(1, 30) # 4. map 类型 demo.mpsi['k1'] = 100 demo.mpsi['k2'] = 200 demo.mpsi['k3'] = 300 print(demo) # 5. 其他方法 print('对象大小:', demo.ByteSize()) # demo = Demo(name="张三", # numb=100, # week=Week.Thu, # rept=[10, 20, 30], # mpsi={'v1': 100, 'v2': 200}, # cust=Custom(attr1=11, attr2=22)) # 2. 对象序列化 def test02(): demo = Demo(name='张三', numb=100, week=Week.Thu, rept=[10, 20], mpsi={'v1': 100, 'v2': 200}, cust=Custom(attr1=11, attr2=22)) # 1. 序列化为二进制数据 data = demo.SerializeToString() print(data) open('data.bin', 'wb').write(data) # 2. 序列化为 json 格式 json = json_format.MessageToJson(demo) print(json) open('data.json', 'w').write(json) # 3. 对象反序列化 def test03(): # 1. 反序列化二进制数据 demo = Demo() data = open('data.bin', 'rb').read() demo.ParseFromString(data) print(demo) print('-' * 30) # 反序列化 json 数据 data = open('data.json', 'r').read() demo = json_format.Parse(data, Demo()) print(demo) if __name__ == '__main__': test01() test02() test03()