目录
- 下载安装Protobuf
- 定义数据格式
- Java代码序列化
- Python反序列化
Protobuf(Protocol Buffers)是由 Google 开发的一种轻量级、高效的数据交换格式
- 官方文档:https://protobuf.dev/overview/
- GitHub:https://github.com/protocolbuffers/protobuf
- https://github.com/protocolbuffers/protobuf/releases/latest
- VSCode语法高亮插件:vscode-proto
本文仅做一个简单的代码演示,并不涉及原理说明
本文演示如何将Java数据通过文件的方式传递给Python
项目结构
protobuf-demo/
protobuf-data # 定义通用的数据结构
protobuf-java # Java项目序列化protobuf
protobuf-python # Python项目反序列化protobuf
下载安装Protobuf
# 检查系统版本
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.14.4
BuildVersion: 18E2035
# 下载解压 protoc-23.0-osx-x86_64.zip
$ ./bin/protoc --version
libprotoc 23.0
定义数据格式
protobuf-data/addressbook.proto
// 文件:addressbook.proto
// 指定 Protobuf 版本为版本3
syntax = "proto3";
// 指定 protobuf 包名,防止有相同类名的 message 定义
package com.example.protobuf;
// 是否生成多个文件
option java_multiple_files = true;
// 生成的文件存放在哪个包下
option java_package = "com.example.protobuf";
// 生成的类名,如果没有指定,会根据文件名自动转驼峰来命名
option java_outer_classname = "AddressBookProtos";
message Person {
// =1,=2 作为序列化后的二进制编码中的字段的唯一标签,也因此,1-15 比 16 会少一个字节,所以尽量使用 1-15 来指定常用字段。
optional int32 id = 1;
optional string name = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
optional string number = 1;
optional PhoneType type = 2;
}
repeated PhoneNumber phones = 4;
}
message AddressBook {
repeated Person people = 1;
}
使用 Protobuf 提供的编译器,可以将 .proto 文件编译成各种语言的代码文件(如 Java、C++、Python 等)。
Java代码序列化
依赖
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.22.3</version>
</dependency>
生成java代码
./bin/protoc --java_out=../protobuf-java/src/main/java ./addressbook.proto
项目结构
$ tree
.
├── pom.xml
├── protobuf-java.iml
└── src
├── main
│ └── java
│ └── com
│ └── example
│ └── protos
│ ├── AddressBook.java
│ ├── AddressBookOrBuilder.java
│ ├── AddressBookProtos.java
│ ├── Person.java
│ └── PersonOrBuilder.java
└── test
└── java
└── com
└── example
构建测试
package com.example;
import com.example.protos.AddressBook;
import com.example.protos.Person;
import org.junit.Test;
public class ProtobufTest {
@Test
public void testBuildProtobuf(){
// 构建
AddressBook addressBook = AddressBook
.newBuilder()
.addPeople(Person.newBuilder()
.setId(2)
.setName("小明")
.setEmail("yyds@126.com")
.addPhones(Person.PhoneNumber.newBuilder()
.setNumber("18388888888")
.setType(Person.PhoneType.HOME)
)
)
.build();
System.out.println(addressBook);
}
}
输出
people {
id: 2
name: "\345\260\217\346\230\216"
email: "yyds@126.com"
phones {
number: "18388888888"
type: HOME
}
}
序列化
// 序列化成字节数组
byte[] byteArray = addressBook.toByteArray();
// 反序列化 - 字节数组转对象
AddressBook addressBook2 = AddressBook.parseFrom(byteArray);
System.out.println("字节数组反序列化:");
System.out.println(addressBook2);
// 序列化到文件
addressBook.writeTo(new FileOutputStream("AddressBook.txt"));
// 读取文件反序列化
AddressBook addressBook3 = AddressBook.parseFrom(new FileInputStream("AddressBook.txt"));
System.out.println("文件读取反序列化:");
System.out.println(addressBook3);
AddressBook.txt
)小明yyds@126.com"
18388888888
Python反序列化
安装依赖
pip install protobuf
生成Python代码
./bin/protoc --python_out=../protobuf-python ./addressbook.proto
目录
$ tree -I venv
.
├── AddressBook.txt # 由上一步java代码输出的数据文件
├── addressbook_pb2.py # 自动生成的文件
└── demo.py
反序列化示例 demo.py
# -*- coding: utf-8 -*-
"""
@File : demo.py
@Date : 2023-05-12
"""
import addressbook_pb2
if __name__ == '__main__':
# 反序列化
with open('AddressBook.txt', 'rb') as f:
addressBook = addressbook_pb2.AddressBook()
addressBook.ParseFromString(f.read())
for person in addressBook.people:
print(person.name)
# 小明
直接打印addressBook对象
people {
id: 2
name: "\345\260\217\346\230\216"
email: "yyds@126.com"
phones {
number: "18388888888"
type: HOME
}
}
Python的体验不是很好,代码提示的能力基本为零,需要使用dir(obj)
查看对象属性才知道
完整代码:https://github.com/mouday/protobuf-demo
参考
Protobuf: 高效数据传输的秘密武器
Python使用protobuf序列化和反序列化