Protocol Buffers (protobuf) 是一种由 Google 开发的轻便、高效的结构化数据序列化格式,常用于数据存储或在应用程序之间传输数据。它可以将数据结构(如对象、消息)转换为字节流,以便在网络上进行传输或存储。
Protobuf序列化基本流程
-
定义消息结构: 首先,定义消息结构。消息结构通常使用
.proto
文件来描述。该文件使用一种类似于结构体定义的语言来指定消息中的字段以及字段的类型。 -
编译
.proto
文件: 使用protoc
编译器将.proto
文件编译成目标编程语言的源代码(例如 C++, Java, Python 等)。这样可以在代码中使用自动生成的类进行数据的序列化和反序列化。 -
序列化: 使用自动生成的类和方法,将数据对象序列化为字节流(
byte[]
)。 -
反序列化: 将字节流反序列化回消息对象。
示例
1. 定义 .proto
文件
假设我们有一个简单的消息结构,表示一个人,包含姓名、年龄和邮箱
syntax = "proto3";message Person {string name = 1;int32 id = 2;string email = 3;
}
syntax = "proto3";
表示使用 Protobuf 版本 3 语法。message
用于定义消息类型,Person
是消息类型的名称。- 每个字段有一个类型(如
string
,int32
等)和一个唯一的字段编号(如1
,2
,3
等)。
2. 编译 .proto
文件
使用 protoc
命令将 .proto
文件编译为目标编程语言的代码。例如,若要生成 Python 代码:
protoc --python_out=. person.proto
这将生成一个 person_pb2.py
文件,该文件包含一个 Person
类,用于在 Python 中处理序列化和反序列化。
3. 序列化和反序列化(Python 示例)
序列化:将数据对象转换为字节流
import person_pb2# 创建 Person 对象
person = person_pb2.Person()
person.name = "Alice"
person.id = 1234
person.email = "alice@example.com"# 序列化为字节流
serialized_data = person.SerializeToString()# 打印序列化的字节数据
print(serialized_data)
反序列化:将字节流转换回数据对象
# 假设我们收到一个序列化的字节流
received_data = serialized_data# 创建一个新的 Person 对象来存储反序列化的数据
received_person = person_pb2.Person()
received_person.ParseFromString(received_data)# 打印反序列化后的数据
print(f"Name: {received_person.name}")
print(f"ID: {received_person.id}")
print(f"Email: {received_person.email}")
常见操作
-
序列化到文件: 可以将序列化后的字节流保存到文件中,以便以后读取。
-
从文件读取并反序列化: 可以从文件中读取序列化的数据并进行反序列化。
with open("person_data.bin", "wb") as f:f.write(serialized_data)
with open("person_data.bin", "rb") as f:data_from_file = f.read()received_person.ParseFromString(data_from_file)
优势
- 高效性:Protobuf 生成的字节流非常紧凑,比 JSON 或 XML 更节省空间和带宽。
- 跨语言支持:支持多种编程语言,包括 C++, Java, Python, Go 等,便于在不同平台和语言间传输数据。
- 灵活性:可以轻松地添加新字段,而不会破坏与旧版本的兼容性。
- 向后兼容:支持向后兼容,即使你修改了
.proto
文件,旧的代码仍然可以正常工作。
总结
Protobuf 是一种非常高效、跨平台、易于使用的序列化工具,广泛用于数据存储、RPC 和微服务通信等场景。它通过定义 .proto
文件来描述数据结构,然后使用编译器生成目标语言的代码,最后通过 SerializeToString
方法序列化数据,通过 ParseFromString
方法反序列化数据。
遇到问题
1,protoc --python_out=. person.proto 执行命令失败
原因:没有安装 protoc
解决方案:
说明:
以上是两种方案,a和b,我用a方案可行
两个步骤
1,下载 2,解压后,移动文件
上文中描述添加到环境变量,我用的是mac,环境变量即: /usr/local/bin/
完整命令如下:
sudo mv /Users/shenke/Downloads/protoc-28.3-osx-x86_64/bin/protoc /usr/local/bin/
查看版本如下:
2, protoc --python_out=. person.proto 执行命令失败,找不到文件,路径不对
注意,命令格式 =. person.proto,等号= 后面是 点+ 空格
不用写全路径
在ter终端中运行即可
-------继续跟踪,执行如下命令均失败,当前路径,和全路径
protoc --java_out=. UserProto.proto
protoc --java_out=. /Users/shenke/suosuo/src/main/java/com/suosuo/myprojects/protobuf/UserProto.proto
解决方案:ter终端进入到消息文件,所在路径,再执行
protoc --java_out=. UserProto.proto,即可
3,执行生产的文件失败,
生产的python(person_pb2.py)文件失败,如下红框,爆红,无法导入goole.protobuf依赖
导入成功后,如下依赖