最近在做模型的时候发现工程实时落盘的样本是Protobuf序列化后的数据,为了读取这些数据,简单的了解了一下Protobuf。
Protocol Buffers(简称 Protobuf)是一种轻便高效的结构化数据存储格式,可用于结构化数据串行化,很适合进行数据存储和通信协议这样的轻量级应用。类似的还有JSON、XML等。Protobuf独立于语言、平台,同时也易于阅读和理解。这里将以一个例子介绍如何在Python中使用Protobuf。
首先,需要安装了protobuf库。通过以下命令安装:
pip install protobuf
接下来,需要定义一个.proto
文件,描述我们要序列化的数据结构。例如,创建一个名为person.proto
的文件,内容如下:
syntax = "proto3";
message Person {
string name = 1;
int32 age = 2;
string email = 3;
}
proto3
是protobuf的版本。在这个例子中,定义了一个名为Person
的消息,它有三个字段:name
、age
和email
。
当然这里在编写proto文件的时候也有一些小工具来提高我们的效率,比如json转proto:
https://json-to-proto.github.io/
接下来,我们需要编译这个.proto
文件,生成对应的Python代码(c++、java、go也有类似的):
protoc --python_out=. person.proto
这将自动生成一个名为person_pb2.py
的Python文件,其中包含定义的数据结构和序列化/反序列化代码。看一下注释,这个代码不需要编辑(DO NOT EDIT!),直接扔到后面需要使用的地方就行了。
注意:这里的pb2
并不代表proto2
。pb2
是protobuf编译器(protoc
)生成的Python文件的默认命名规则。与protobuf的版本无关。
现在我们可以开始在Python中使用protobuf了。以下是一个简单的示例:
import person_pb2
# 创建一个Person对象并设置字段值
person = person_pb2.Person()
person.name = "张三"
person.age = 30
person.email = "zhangsan@example.com"
# 序列化Person对象为二进制字符串
serialized_person = person.SerializeToString()
print(f"序列化后的数据:{serialized_person}")
# 反序列化二进制字符串为一个新的Person对象
new_person = person_pb2.Person()
new_person.ParseFromString(serialized_person)
# 输出新的Person对象的字段值
print(f"反序列化后的数据:姓名={new_person.name}, 年龄={new_person.age}, 邮箱={new_person.email}")
运行结果:
注意:需要导入了person_pb2
模块(上一步生成的python文件)
建议直接看官方API:https://protobuf.dev/reference/
下面也列举了一些常用的API,其中protobuf_data
为python生成的对象。比如person = person_pb2.Person()
里面的person
。
API | 描述 | 示例 |
---|---|---|
SerializeToString() | 将 Protobuf 对象序列化为二进制字符串 | serialized_data = protobuf_data.SerializeToString() |
ParseFromString(data) | 将二进制字符串反序列化为 Protobuf 对象 | protobuf_data.ParseFromString(serialized_data) |
MergeFromString(data) | 将二进制字符串合并到现有的 Protobuf 对象 | protobuf_data.MergeFromString(serialized_data) |
SerializePartialToString() | 将 Protobuf 对象序列化为二进制字符串,即使某些必需字段未设置 | serialized_data = protobuf_data.SerializePartialToString() |
IsInitialized() | 检查 Protobuf 对象的所有必需字段是否已设置 | protobuf_data.IsInitialized() |
ListFields() | 返回一个包含 Protobuf 对象已设置字段的List | fields = protobuf_data.ListFields() |
Clear() | 清除 Protobuf 对象的所有字段值,将其重置为初始状态 | protobuf_data.Clear() |
ClearField(field_name) | 删除 Protobuf 对象中指定字段的值 | protobuf_data.ClearField("field_name") |
HasField(field_name) | 检查 Protobuf 对象中的指定字段是否已设置 | protobuf_data.HasField("field_name") |
在上面的基础上,将 Protobuf 对象序列化为二进制字符串可以保存至pb文件,方法很简单,和写文本文档的方法一样:
with open('test.pb', 'wb') as fb:
fb.write(serialized_person)
其中serialized_person
为上面序列化为二进制字符串。这样保存下来的文件大概是这样:
但是Protobuf 序列化后的数据是二进制格式,通常无法直接以文本形式展示(或者看起来很奇怪)。因此将二进制数据转换为 Base64 编码的字符串是一种常见的做法, Base64 编码后的字符串可以在文本协议(如电子邮件、JSON、XML等)中传输和存储。因此以上代码修改为:
import base64
with open('test.pb', 'wb') as fb:
fb.write(base64.b64encode(serialized_person))
这样保存的就是Base64编码后的结果了。(使用的时候注意需要先用Base64解码)
参考:
https://protobuf.dev/getting-started/pythontutorial/
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。