前言
在學習Netty時,發現可以整合ProtoBuf相關的處理器,所以先來學習一下ProtoBuf相關知識。
關於ProtoBuf
ProtoBuf可以看做一個序列化(對象轉成字節數組)和反序列化(字節數組轉成對象)工具。相比Java本身的序列化,ProtoBuf可以支持跨語言,如使用Java序列化,使用Python來反序列化。相比XML這個文件格式,ProtoBuf序列化生成的數據更小,傳輸效率更高。
下載編譯器
github地址,這里我們下載windows版本的編譯器protoc-3.20.0-win64.zip,解壓即可用。
定義proto文件
syntax = "proto3";
package tutorial;
option java_package = "com.imooc.sourcecode.java.google.protobuf.test1";
option java_outer_classname = "PersonProto";
message Person {
optional string name = 1;
optional int32 email = 2;
enum PhoneType {
MOBILE = 0;
HOME = 1;
}
message PhoneNumber {
optional string number = 1;
optional PhoneType type = 2;
}
repeated PhoneNumber phones = 4;
}
syntax = "proto3" 表示使用proto3版本,默認使用proto2版本。
optional 表示當前字段可選,非必填。
string name = 1 每個字段需要有一個唯一的號碼,必須大於0。
enum 表示枚舉類型。
repeated 表示可重復,Java中就是List。
message 可以看做一個Java類,可以嵌套。
Java處理
添加maven依賴
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.19.4</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>3.19.4</version>
<scope>runtime</scope>
</dependency>
根據proto文件創建Java序列化和反序列化代碼
protoc -I=$SRC_DIR --java_out=$DST_DIR person.proto
-I表示proto文件的路徑,--java_out表示生成代碼的路徑,實際命令為
.\protoc.exe -I=D:\java\code_resp\github_resp\source_code\src\main\java\com\imooc\sourcecode\java\google\protobuf\test1 --java_out=D:\java\code_resp\github_resp\source_code\src\main\java person.proto
--java_out值不要包含具體的包路徑,proto文件中已經配置了。
將對象序列化到文件中
import com.imooc.sourcecode.java.google.protobuf.test1.PersonProto.Person;
import com.imooc.sourcecode.java.google.protobuf.test1.PersonProto.Person.PhoneNumber;
import com.imooc.sourcecode.java.google.protobuf.test1.PersonProto.Person.PhoneType;
import java.io.FileOutputStream;
import java.io.IOException;
public class Client {
public static void main(String[] args) throws IOException {
PhoneNumber phoneNumber = PhoneNumber.newBuilder()
.setNumber("2")
.setType(PhoneType.HOME)
.build();
Person person = Person.newBuilder()
.setName("lisi")
.setEmail(12)
.addPhones(phoneNumber)
.build();
person.writeTo(new FileOutputStream("D:/testjar/java_serialize_person"));
}
}
使用Builder模式創建Person對象並序列化到文件中。
將Python序列化的文件反序列化為對象
import com.imooc.sourcecode.java.google.protobuf.test1.PersonProto.Person;
import java.io.FileInputStream;
import java.io.IOException;
public class Client2 {
public static void main(String[] args) throws IOException {
Person person = Person.parseFrom(new FileInputStream("D:/testjar/python_serialize_person"));
System.out.println(person);
}
}
讀取文件並反序列化為對象。
Python處理
安裝依賴
pip install protobuf
PyCharm中可以這樣安裝

根據proto文件創建Python序列化和反序列化代碼
protoc -I=$SRC_DIR --python_out=$DST_DIR person.proto
-I表示proto文件的路徑,--python_out表示生成代碼的路徑,實際命令為
.\protoc.exe -I=D:\java\code_resp\PycharmProjects\test_protobuf\protobuf --python_out=D:\java\code_resp\PycharmProjects\test_protobuf\protobuf person.proto
將Java序列化的文件反序列化為對象
import person_pb2
def test_deserialize():
with open("D:/testjar/java_serialize_person", "r") as rf:
bytes_read = rf.read()
person = person_pb2.Person()
# 需要將字符串轉成字節數組
person.ParseFromString(bytes_read.encode())
print(person)
return
if __name__ == "__main__":
test_deserialize()
pass
從文件中讀取到的是字符串類型,需要轉成字節數組類型,核心為ParseFromString()方法。
將對象序列化到文件中
import person_pb2
def test_serialize():
person = person_pb2.Person()
person.name = "zhangsan"
person.email = 34
phone = person.phones.add()
phone.number = "3"
phone.type = person.PhoneType.MOBILE
with open("D:/testjar/python_serialize_person", "wb") as f:
f.write(person.SerializeToString())
return
if __name__ == "__main__":
test_serialize()
pass
創建一個Person對象並序列化到文件中,核心為SerializeToString()方法。
總結
通過上述測試,我們可以發現,Java序列化的文件通過Python是可以反序列化成功的,Python序列化的文件通過Java也是可以反序列化成功的。更多ProtoBuf相關用法,請查看官方文檔。
參考
Protocol Buffers
protobuf(proto3)極簡入門(python為例)
深入 ProtoBuf - 簡介