Python读取及生成pb文件,pb与jsonStr互转,pb与dictJson互转,打包.exe/.sh并转换,很完美跨平台

  1. 读取pb及生成pb文件
  2. pb文件转jsonString
  3. 二进制pb转jsonString
  4. 二进制pb转jsonDict
  5. jsonString转pb
  6. jsonDict转pb
  7. 赋值(有空或者类型不对应会无法赋值及报错)
  8. 打包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)

参考

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序媛一枚~

您的鼓励是我创作的最大动力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值