Python读取及生成pb文件,pb与jsonStr互转,pb与dictJson互转,打包.exe/.sh并转换,很完美跨平台
- 1. 效果图
- 2. 命令行:proto文件转.class(绝对路径或相对路径)
- 3. 序列化、反序列化api
- 4. pb转json,json转pb,pb转dict
- 5. 打包.exe/.sh并调用
- 6. 源代码
- 6.1 addressbook.proto
- 6.2 pb2json.py
- 参考
- 读取pb及生成pb文件
- pb文件转jsonString
- 二进制pb转jsonString
- 二进制pb转jsonDict
- jsonString转pb
- jsonDict转pb
- 赋值(有空或者类型不对应会无法赋值及报错)
- 打包exe/sh
1. 效果图
读取pb文件并解析为jsonStr打印
2. 命令行:proto文件转.class(绝对路径或相对路径)
d:
cd D:\study\python-scripts\p20230731\pb2json
protoc -I=D:\study\python-scripts\p20230731\pb2json\ --python_out=D:\study\python-scripts\p20230731\pb2json\ D:\study\python-scripts\p20230731\pb2json\addressbook.proto
d:
cd D:\study\python-scripts\p20230731\pb2json
protoc -I=. --python_out=./ ./addressbook.proto
效果图如下:
执行成功后会在本地生成: addressbook_pb2.py
Java 和 Python不一致的地方,Java可以指定包名,类名(.proto名称可以随意);会自适应生成相应的JavaPB对象
Python可以指定包名,不指定类名(.proto名称固定),默认为 aaa.proto 则生成 aaa_pb2.py类
3. 序列化、反序列化api
- IsInitialized():检查是否已设置所有必填字段。
- str():返回消息的人类可读表示形式, 对于调试特别有用。(通常调用为 str(message) 或 print message.)
- CopyFrom(other_msg):用给定消息的值。
- Clear():将所有元素清除回空状态。
协议缓冲区类有用于写入和读取消息的方法 使用协议缓冲区的所选类型 二进制格式 。这些 包括:
- SerializeToString():序列化消息并将其作为字符串返回。 请注意,字节是二进制的,而不是文本的;我们只使用 str 键入为 方便的容器。
- ParseFromString(data):从给定字符串解析消息
4. pb转json,json转pb,pb转dict
google.protobuf.json_format
https://googleapis.dev/python/protobuf/latest/google/protobuf/json_format.html
5. 打包.exe/.sh并调用
windows下到打包
pyinstaller pb2json.py
上边的语句可能会报错: Error loading Python DLL
‘C:\Users\ADMINI~1\AppData\Local\Temp_MEI41642\python310.dll’
LoadLibrary:找不到指定的模块。
用下边的语句ok:
pyinstaller --onefile pb2json.py
linux平台打包则得到可在linux平台运行的二进制可执行文件
6. 源代码
6.1 addressbook.proto
syntax = "proto3";
package tutorial;
message Person {
string name = 1;
int32 id = 2;
string email = 3;
enum PhoneType {
PHONE_TYPE_UNSPECIFIED = 0;
PHONE_TYPE_MOBILE = 1;
PHONE_TYPE_HOME = 2;
PHONE_TYPE_WORK = 3;
}
message PhoneNumber {
string number = 1;
PhoneType type = 2;
}
repeated PhoneNumber phones = 4;
}
message AddressBook {
repeated Person people = 1;
}
6.2 pb2json.py
#!/usr/bin/env python3
import json
import sys
from google.protobuf import json_format
import addressbook_pb2
if len(sys.argv) == 2:
print("Usage:", sys.argv[0], sys.argv[1], "address_file")
print('--------------------------------------------------------')
pb_path = sys.argv[1]
address = addressbook_pb2.AddressBook()
# 从已经存在的文件读取pb
try:
with open(pb_path, "rb") as f:
address.ParseFromString(f.read())
except IOError:
print(pb_path + ": Could not open file...")
# pb转json
json_string = json_format.MessageToJson(address)
print('json_string: ', json_string)
print('--------------------------------------------------------')
address_book = addressbook_pb2.AddressBook()
# person = addressbook_pb2.Person() # 初始化方式1
person = address_book.people.add() # 初始化方式2
person.id = 1234
person.name = "John Doe"
person.email = "jdoe@example.com"
phone = person.phones.add()
phone.number = "555-4321"
phone.type = addressbook_pb2.Person.PHONE_TYPE_HOME
person2 = address_book.people.add() # 初始化方式2
person2.id = 1314
person2.name = "Lucy"
person2.email = "Lucy@example.com"
phone2 = person2.phones.add()
phone2.number = "010-4321"
phone2.type = addressbook_pb2.Person.PHONE_TYPE_WORK
# 请注意,这些赋值不仅仅是向 通用 Python 对象。如果要尝试分配未定义的字段 在 .proto 文件,一个 AttributeError 会被提出来。
# 如果分配字段 对于错误类型的值,a TypeError 将被提出。另外,阅读 字段在设置之前的值将返回默认值。
try:
person.no_such_field = 1 # raises AttributeError
person.id = "1234" # raises TypeError
except AttributeError as e:
print('AttributeError:', e)
except TypeError as e:
print('TypeError:', e)
try:
person.id = "1234" # raises TypeError
except TypeError as e:
print('TypeError:', e)
# 序列化以string返回
str = address_book.SerializeToString()
print('str: ', str)
# 从文件读取pb,并打印所有属性
pb_path = 'addressbook.pb'
with open(pb_path, 'wb') as f:
f.write(str)
# 遍历所有的字段及对象属性
def ListPeople(address_book):
for person in address_book.people:
print("Person ID:", person.id)
print(" Name:", person.name)
if person.email is not None:
print(" E-mail address:", person.email)
for phone_number in person.phones:
if phone_number.type == addressbook_pb2.Person.PhoneType.PHONE_TYPE_MOBILE:
print(" Mobile phone #: ", end="")
elif phone_number.type == addressbook_pb2.Person.PhoneType.PHONE_TYPE_HOME:
print(" Home phone #: ", end="")
elif phone_number.type == addressbook_pb2.Person.PhoneType.PHONE_TYPE_WORK:
print(" Work phone #: ", end="")
print(phone_number.number)
address_book = addressbook_pb2.AddressBook()
# 读取已经存在的文件
with open(pb_path, "rb") as f:
address_book.ParseFromString(f.read())
# 遍历打印所有属性
ListPeople(address_book)
# pb转json
json_string = json_format.MessageToJson(address_book)
print('pb2json_string: ', json_string)
pb_json_path = pb_path.replace(".pb", "_pb.json")
with open(pb_json_path, 'w') as f:
f.write(json_string)
# json_str 转pb对象
address2 = addressbook_pb2.AddressBook()
json_format.Parse(json_string,address2)
print('json_str2pb: ',address2)
# pb转dict
json_dict = json_format.MessageToDict(address_book)
print("pb2json_dict: ", json_dict)
pb_dict_path = pb_path.replace(".pb", "_pb_dict.json")
with open(pb_dict_path, 'w') as f:
f.write(json.dumps(json_dict))
# json_dict 转pb
address3 = addressbook_pb2.AddressBook()
json_format.Parse(json_string,address3)
print('json_dict2pb: ',address3)
参考
- https://protobuf.dev/getting-started/pythontutorial/
- https://googleapis.dev/python/protobuf/latest/google/protobuf/json_format.html