Protocol Buffers - 基本應用



概述

現在讓我們使用 Google Protocol Buffer,看看它如何與簡單的問候應用一起工作。在這個例子中,我們將建立一個簡單的應用程式,它將執行以下操作:

  • 問候編寫者:

    • 從使用者處獲取問候語和使用者名稱

    • 將上述資訊儲存到磁碟上的檔案中

  • 問候讀取者:

    • 讀取我們在上面儲存的同一檔案

    • 將資料轉換為物件並列印資料

Protocol Buffer 定義檔案

Protocol Buffer 的“定義檔案”包含我們想要序列化的資料的模式定義。資料儲存在一個人類可讀的檔案中,副檔名為 **".proto"**。

讓我們將以下資料儲存在 **greeting.proto** 中,我們將在我們的第一個應用程式中使用它。

syntax = "proto3";
package tutorialspoint;
option java_package = "com.tutorialspoint.greeting";

message Greet {
   string greeting = 1;
   string username = 2;
}

理解每個結構

現在,讓我們仔細看看資料,並瞭解上面程式碼塊中每一行程式碼的作用。

syntax = "proto3";

這裡的 **syntax** 表示我們正在使用哪個版本的 Protobuf。因此,我們使用的是最新版本 3,因此模式可以使用所有對版本 3 有效的語法。

package tutorialspoint;

這裡的 **package** 用於衝突解決,例如,如果我們有多個同名的類/成員。

option java_package = "com.tutorialspoint.greeting";

此引數特定於 Java,即從 **.proto** 檔案自動生成的程式碼所在的包。

message Greet

將要建立/重新建立的物件的基類的名稱。

string greeting = 1;
string username = 2;

這些是 **Greet** 類的屬性,以及資料型別和模式中標籤的位置。如果要新增新的標籤,其位置應為“3”。請注意,此位置整數對於確保實際資料緊湊且存在模式演變的空間非常重要。

Protocol Buffer 程式碼生成

現在我們已經定義了,讓我們安裝我們將用於為上述 **Greet** 類自動生成程式碼的“proto”二進位制檔案。可以在 "https://github.com/protocolbuffers/protobuf/releases/" 找到這些二進位制檔案。

根據作業系統選擇正確的二進位制檔案。我們將在 Windows 上安裝 proto 二進位制檔案,但 Linux 的步驟差別不大。

我們下載了 https://github.com/protocolbuffers/protobuf/releases/download/v27.3/protoc-27.3-win64.zip

驗證 Proto 編譯器設定

安裝後,確保您可以透過命令列訪問它:

protoc --version

libprotoc 27.3

這確認 Protobuf 已正確安裝。現在讓我們繼續為 Java 建立上面描述的問候應用程式。

專案結構

這是我們將擁有的整體專案結構:

Project Structure

Java 中的問候應用程式

現在我們已經安裝了 **protoc**,我們可以使用 **protoc** 從 proto 檔案自動生成程式碼。讓我們先建立一個 Java 專案。

以下是我們將用於 Java 專案的 Maven 配置。請注意,它還包含 **Protobuf-java** 的必需庫。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.tutorials.point</groupId>
   <artifactId>protobuf-tutorial</artifactId>
   <version>1.0</version>
   <packaging>jar</packaging>

   <properties>
      <maven.compiler.source>21</maven.compiler.source>
      <maven.compiler.target>21</maven.compiler.target>
   </properties>

   <dependencies>
      <!-- https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java -->
      <dependency>
         <groupId>com.google.protobuf</groupId>
         <artifactId>protobuf-java</artifactId>
         <version>4.27.3</version>
      </dependency>
   </dependencies>

   <build>
      <plugins>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.2.4</version>
            <configuration>
               <!--Put your configurations here-->
            </configuration>
            <executions>
               <execution>
                  <phase>package</phase>
                     <goals>
                     <goal>shade</goal>
                  </goals>
               </execution>
            </executions>
         </plugin>
      </plugins>
   </build>
</project>

我們所有的程式碼都將位於 **src/main/java** 下。

在專案結構完成後,讓我們生成 **Greet** 類的程式碼:

生成 Java 類

protoc --java_out=. greeting.proto

命令執行後,您會在當前目錄內的 **com > tutorialspoint > greeting** 資料夾下看到一個自動生成的類。

  • Greeting.java

此檔案包含一個類 **Greeting** 和一個介面 **GreetOrBuilder**,它將幫助我們對 **Greet** 物件進行序列化和反序列化。

使用生成的 Java 類

現在,讓我們 **編寫** 資料的寫入器,它將接收 **使用者名稱** 和 **問候語** 作為輸入:

GreetWriter.java

package com.tutorialspoint.greeting;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import com.google.flatbuffers.FlatBufferBuilder;

public class GreetWriter {
	public static void main(String[] args) throws FileNotFoundException, IOException {
		// create a flat buffer builder
		// it will be used to create Greet FlatBuffer
		FlatBufferBuilder builder = new FlatBufferBuilder(1024);
		
		// read greeting and username from console
		int greeting = builder.createString(args[0]);
		int username = builder.createString(args[1]);
		
		// create Greet FlatBuffers using startGreet() method
		Greet.startGreet(builder);
		// add the greeting and username to the Greet FlatBuffer
		Greet.addGreeting(builder, greeting);
		Greet.addUsername(builder, username);
		
		// mark, data being entered in Greet FlatBuffer
		int greet = Greet.endGreet(builder);
		
		// finish the builder
		builder.finish(greet);
		
		// get the bytes to be stored
		byte[] data = builder.sizedByteArray();
		
	      String filename = "greeting_flatbuffers_output";
	      System.out.println("Saving greeting to file: " + filename);
		// write the builder content to the file named	greeting_flatbuffers_output
	      try(FileOutputStream output = new FileOutputStream(filename)){
	    	  output.write(data);
	      }
	      System.out.println("Saved greeting with following data to disk: \n" + greeting);
	}
}

寫入器只需獲取 CLI 引數,建立 **Greet** 物件,將其序列化,然後將其轉儲到檔案中。

現在讓我們編寫一個將讀取檔案的 **讀取器**:

GreetReader.java

package com.tutorialspoint.greeting;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import com.google.flatbuffers.FlatBufferBuilder;

public class GreetReader {
	public static void main(String[] args) throws FileNotFoundException, IOException {
		// create a flat buffer builder
		// it will be used to read Greet FlatBuffer
		FlatBufferBuilder builder = new FlatBufferBuilder(1024);
		 String filename = "greeting_flatbuffers_output";
	      System.out.println("Reading from file " + filename);
		    
	      try(FileInputStream input = new FileInputStream(filename)) {
	    	  // get the serialized data
	         byte[] data = input.readAllBytes();
	         java.nio.ByteBuffer buf = java.nio.ByteBuffer.wrap(data);
	         // read the root object in serialized data
	         Greet greet = Greet.getRootAsGreet(buf);
	    	 
	         // print greet values 
	         System.out.println("Greeting: " + greet.greeting() + "\n" + "Username: " + greet.username());
	      }		
	}
}

讀取器只需從同一檔案讀取,對其進行反序列化,然後列印有關問候語的資料。

編譯專案

現在我們已經設定了讀取器和寫入器,讓我們編譯專案。

mvn clean install

序列化 Java 物件

現在,讓我們首先執行寫入器以將物件序列化到檔案系統。

java -cp .\target\protobuf-tutorial-1.0.jar com.tutorialspoint.greeting.GreetWriter Hello John

Saving greeting to file: 
greeting_protobuf_output

Saved greeting with following data to disk:
greeting: Hello
username: John

反序列化序列化的物件

然後,讓我們執行讀取器以從檔案系統反序列化物件。

java -cp .\target\protobuf-tutorial-1.0.jar com.tutorialspoint.greeting.GreetReader

Reading from file greeting_protobuf_output
Greeting: Hello
Username: John

因此,正如我們所看到的,寫入器序列化並儲存到檔案中的資料,被讀取器正確地反序列化並相應地打印出來。

Python 中的問候應用程式

現在讓我們將同一個示例編寫為 Python 專案:

安裝 Protocol Buffers 庫

在我們繼續之前,我們需要安裝 **protobuf pip 包**。

pip install protobuf

我們所有的程式碼都將位於 **python** 目錄下。

Project Structure Python

從 proto 檔案生成 Python 類

在專案結構完成後,讓我們生成 Greet 類的程式碼:

protoc  --python_out=. greeting.proto

執行此命令後,您會在當前目錄中看到一個自動生成的類 **greeting_pb2.py**。此類將幫助我們對 **Greet** 物件進行序列化和反序列化。

使用生成的 Python 類

現在,讓我們 **編寫** 資料的寫入器,它將接收 **使用者名稱** 和 **問候語** 作為輸入:

greetWriter.py

import greeting_pb2

import sys

greet = greeting_pb2.Greet()
greet.username = sys.argv[1]
greet.greeting = sys.argv[2]

filename = "greeting_protobuf_output";
print("Saving to file: " + filename)

f = open(filename, "wb")
f.write(greet.SerializeToString())
f.close()
print("Saved following greeting to disk: \n" + str(greet))

寫入器只需獲取 CLI 引數,建立 **Greet** 物件,將其序列化,然後將其轉儲到檔案中。

現在讓我們建立一個將讀取檔案的 **讀取器**:

greetReader.py

import greeting_pb2

greet = greeting_pb2.Greet()

filename = "greeting_protobuf_output";
print("Reading from file: " + filename)

f = open(filename, "rb")
greet.ParseFromString(f.read())
f.close()

print("Read greeting from disk: \n" + str(greet))

讀取器只需從同一檔案讀取,對其進行反序列化,然後列印有關問候語的資料。

序列化 Python 物件

現在,讓我們首先執行 **寫入器**。

py greetWriter.py Hola Jane

Saving to file: greeting_protobuf_output
Saved following greeting to disk:
greeting: "Hola"
username: "Jane"

反序列化 Python 物件

然後,讓我們執行 **讀取器**。

python greetReader.py

Reading from file: greeting_protobuf_output
Read greeting from disk:
greeting: "Hola"
username: "Jane"

因此,正如我們所看到的,寫入器序列化並儲存到檔案中的資料,同樣,這些資料被讀取器正確地反序列化並相應地打印出來。

廣告
© . All rights reserved.