Protobuf - 基本应用程序
现在让我们使用 Google Protocol Buffer,看看它如何与简单的 Greeting 应用程序配合使用。在这个例子中,我们将创建一个简单的应用程序,它将执行以下操作 −
问候写入者 −
从用户那里获取问候语和用户名
将上述信息存储在磁盘中的文件中
问候读取者 −
读取我们存储在上述文件中的相同文件
将该数据转换为对象并打印数据
协议缓冲区定义文件
协议缓冲区"定义文件"包含我们要序列化的数据的模式定义。数据存储在扩展名为 ".proto" 的人类可读文件中。
让我们将以下数据存储在 "greeting.proto" 中,我们将在我们的第一个应用程序中使用它。
syntax = "proto3"; package tutorial; option java_package = "com.tutorialspoint.greeting"; message Greet { string greeting = 1; string username = 2; }
现在,让我们仔细看看数据,看看上面代码块中每行代码的作用。
syntax = "proto3";
这里的"syntax"代表我们正在使用的 Protobuf 版本。因此,我们使用最新版本 3,因此模式可以使用对版本 3 有效的所有语法。
package tutorial;
这里的package用于解决冲突,例如,我们有多个同名的类/成员。
option java_package = "com.tutorialspoint.greeting";
此参数特定于 Java,即,将自动生成".proto"文件中的代码的包。
message Greet
将创建/重新创建的对象的基类的名称。
string Greeting = 1; string username = 2;
这些是 Greet 类的属性以及数据类型和标签在架构中的位置。如果要添加新标签,则其位置应为"3"。请注意,此位置整数对于确保实际数据紧凑且存在模式演变范围非常重要。
协议缓冲区代码生成
现在我们已经定义,让我们安装"proto"二进制文件,我们将使用它来自动生成上述 Greet 类的代码。二进制文件可以在 "https://github.com/protocolbuffers/protobuf/releases/"
找到。根据操作系统选择正确的二进制文件。我们将在 Windows 上安装 proto 二进制文件,但对于 Linux,步骤没有太大不同。
安装后,请确保您能够通过命令行访问它 −
protoc --version libprotoc 3.15.6
它确认 Protobuf 已正确安装。现在让我们转到 创建 上面描述的 Java 问候应用程序。
项目结构
以下是我们将拥有的整体项目结构 −
与各个语言相关的代码转到各自的目录。我们有一个单独的目录来存储我们的"proto"文件。
以下是我们将拥有的 Java 项目结构 −
Java 中的问候应用程序
现在我们已经安装了 protoc,我们可以使用 protoc 从 proto 文件自动生成代码。不过,我们先创建一个 Java 项目。
以下是我们将用于 Java 项目的 Maven 配置。请注意,它还包含 Protobuf 所需的库。
<?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>1.8</maven.compiler.source> <maven.compiler.target>1.8</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>3.15.8</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 类生成代码 −
protoc --java_out=java/src/main/java proto_files/greeting.proto
执行命令后,您会注意到两个自动生成的类。
Greeting.java
GreetOrBuilder.java
这两个类将帮助我们对 Greet 对象进行序列化和反序列化。
现在,让我们 编写 数据的编写器,它将用户名和问候语作为其输入 −
package com.tutorialspoint.greeting; import java.io.FileOutputStream; import java.io.IOException; import com.tutorialspoint.greeting.Greeting.Greet; public class GreetWriter{ public static void main(String[] args) throws IOException { Greet greeting = Greet.newBuilder() .setGreeting(args[0]) .setUsername(args[1]) .build(); String filename = "greeting_protobuf_output"; System.out.println("Saving greeting to file: " + filename); try(FileOutputStream output = new FileOutputStream(filename)){ greeting.writeTo(output); } System.out.println("Saved greeting with following data to disk: " + greeting); } }
writer 仅接受 CLI 参数,创建 Greet 对象,对其进行序列化,然后将其转储到文件中。
现在让我们编写一个 reader 来读取文件 −
package com.tutorialspoint.greeting; import java.io.FileInputStream; import java.io.IOException; import com.tutorialspoint.greeting.Greeting.Greet; public class GreetReader{ public static void main(String[] args) throws IOException { Greet.Builder greetBuilder = Greet.newBuilder(); String filename = "greeting_protobuf_output"; System.out.println("Reading from file " + filename); try(FileInputStream input = new FileInputStream(filename)) { Greet greet = greetBuilder.mergeFrom(input).build(); System.out.println("Greeting: " + greet.getGreeting() + " " + "Username: " + greet.getUsername()); } } }
读取器只是从同一个文件中读取,对其进行反序列化,然后打印有关问候语的数据。
现在我们已经设置了读取器和写入器,让我们编译该项目。
mvn clean install
现在,让我们首先执行写入器。
java -cp . arget\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 . arget\protobuf-tutorial-1.0.jar com.tutorialspoint.greeting.GreetReader Reading from file greeting_protobuf_output Greeting: Hello Username: John
因此,当我们看到由 writer 序列化并保存到文件的数据时,该确切数据已由 reader 正确反序列化并相应地打印。
Python 中的问候应用程序
现在让我们将相同的示例编写为 Python 项目 −
在继续之前,我们需要安装 protobuf pip 包。
pip install protobuf
我们所有的代码都将出现在 "google-protobuf/python" 下。
在项目结构完成后,让我们为 Greet 类生成代码 −
protoc --python_out=python proto_files/greeting.proto
执行此操作后命令,您会注意到 Python 目录下有一个自动生成的类 "*proto_files/greeting_pb2.py"。此类将帮助我们对 Greet 对象进行序列化和反序列化。
现在,让我们编写数据的编写器,它将以 用户名 和 问候语 作为其输入 −
from .proto_files 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: " + str(greet))
writer 仅接受 CLI 参数,创建 Greet 对象,对其进行序列化,然后将其转储到文件中。
现在让我们创建一个 reader 来读取文件 −
from proto_files 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: " + str(greet))
读取器只是从同一个文件中读取,对其进行反序列化,然后打印有关问候的数据。
现在,让我们首先执行写入器。
python greetWriter.py Hola Jane Saving to file: greeting_protobuf_output Saved following greeting to disk: greeting: "Hola" username: "Jane"
And then, let us execute the reader.
python greetReader.py Reading from file: greeting_protobuf_output Read greeting from disk: greeting: "Hola" username: "Jane"
因此,如我们所见,数据由 writer 序列化并保存到文件中。接下来,相同的数据由 reader 正确反序列化并相应地打印。