Google之ProtoBuf簡單使用


前言

在學習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 - 簡介


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM