ProtoBuf 使用
ProtoBuf 全称 protocol buffers,是 google 开源的一个平台无关、语言无关的序列化框架。
官网点击这里 protobuf 官网
文本通过一个简单的案例介绍 protobuf 的简单使用。
创建 addressbook.proto 文件
创建一个 maven 项目,在 resources
下创建一个目录 proto
(可自己更改),然后在该目录下创建一个 addressbook.proto
文件。
syntax = "proto3";
package tutorial;
option java_package = "protobuf.demo.tutorial";
option java_outer_classname = "AddressBookProto";
message Person{
int32 id = 1;
string name = 2;
string email = 3 ;
enum PhoneType{
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber{
string number = 1;
PhoneType type = 2;
}
repeated PhoneNumber phones = 4;
}
message AddressBook{
string bookName = 1;
repeated Person people = 2;
}
syntax 定义 .proto
文件使用的是 proto3 的语法。proto2 和 proto3 的语法区别可以去官网查看。
package 指的是该 .proto
文件里定义的类的包路径。
option java_package指的最终生成的 java 类所在的包名。
option java_outer_classname指的是最终生成的 java 类的名称。
message指的定义的消息类。
enum 定义枚举类。
repeated 指明该字段可以重复添加,在 java 看来该字段是一个 list 集合。
生成 java 类
生成 java 类的方式有很多种,这里用列举两种方式。
maven 插件
编写 maven pom 文件,新增如下内容。
<dependencies>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-all</artifactId>
<version>1.30.1</version>
</dependency>
</dependencies>
<build>
<!--这个是为了下载下面的工具用的,他可以提供一些变量,os.detected.classifier变量可以根据当前系统的类型来下载对应的工具-->
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.6.2</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.5.0</version>
<!--添加.proto文件的编译工具-->
<configuration>
<!--protoc工具通过.proto文件生成对应的java对应的类-->
<protocArtifact>com.google.protobuf:protoc:3.0.0-beta-4:exe:${os.detected.classifier}
</protocArtifact>
<!--protoc-gen-grpc-java工具通过.proto文件生成grpc工具类-->
<pluginArtifact>io.grpc:protoc-gen-grpc-java:0.15.0:exe:${os.detected.classifier}</pluginArtifact>
<!--这是生成grpc工具类存放的文件夹的名字-->
<pluginId>grpc</pluginId>
<!--要编译的.proto文件的路径-->
<protoSourceRoot>src/main/resources/proto</protoSourceRoot>
</configuration>
<executions>
<!--这是上面两个编译工具用到的命令-->
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
引入依赖之后,运行 maven 插件。
运行结束之后在 target
目录下可以看到生成的 java 文件。
编译工具
去官网下载最新的编译工具,传送门点这里。根据自己的操作系统下载。然后运行如下命令:
protoc -I=./src/main/resources/proto/ --java_out=./src/main/java ./src/main/resources/proto/addressbook.proto
-I 指.proto
文件所在目录,**–java_out **指生成的 java 文件所在的目录,后面紧跟.proto
文件。这样生成的文件如下图:
编写测试代码
main 方法如下:
public static void main(String[] args) throws IOException {
File file = new File("address_book.txt");
if (!file.exists() && file.createNewFile()) {
System.out.println("创建了一个新的通讯录" + file.getName());
}
System.out.println("开始新增人员信息");
writeAddressBook(file);
System.out.println("--------------");
System.out.println("开始读取人员信息");
readAddressBook(file);
System.out.println("--------------");
}
生成一个文件,然后写入一个人员信息,再从文件中读取出来。
private static void writeAddressBook(File file) throws IOException {
FileOutputStream outputStream = new FileOutputStream(file);
// 创建一个手机号码
AddressBookProto.Person.PhoneNumber.Builder builder = AddressBookProto.Person.PhoneNumber.newBuilder();
AddressBookProto.Person.PhoneNumber phoneNumber1 = builder
.setNumber("17500001111")
.setType(AddressBookProto.Person.PhoneType.MOBILE)
.build();
builder.clear();
AddressBookProto.Person.PhoneNumber phoneNumber2 = builder
.setNumber("18900002222")
.setType(AddressBookProto.Person.PhoneType.WORK)
.build();
// 创建一个人 韩信
AddressBookProto.Person hanXin = AddressBookProto.Person.newBuilder()
.setId(1)
.setName("韩信")
.setEmail("hanxin@proto.com")
.addPhones(phoneNumber1)
.addPhones(phoneNumber2)
.build();
System.out.println("新增通讯录人员信息成功");
// 将 七七这个人的信息添加到通讯录
AddressBookProto.AddressBook addressBook = AddressBookProto.AddressBook.newBuilder()
.setBookName("七七的通讯录")
.addPeople(hanXin)
.build();
// 持久化
outputStream.write(addressBook.toByteArray());
outputStream.close();
}
private static void readAddressBook(File file) throws IOException {
FileInputStream inputStream = new FileInputStream(file);
AddressBookProto.AddressBook addressBook = AddressBookProto.AddressBook.parseFrom(inputStream);
System.out.println(addressBook.getBookName() + ":");
for (AddressBookProto.Person person : addressBook.getPeopleList()) {
System.out.printf("编号:%d\t姓名:%s\n", person.getId(), person.getName());
List<AddressBookProto.Person.PhoneNumber> phonesList = person.getPhonesList();
System.out.printf("\t%s\t%s\n", "号码类型", "号码");
for (AddressBookProto.Person.PhoneNumber phoneNumber : phonesList) {
System.out.printf("\t%s\t%s\n", phoneNumber.getType(), phoneNumber.getNumber());
}
}
}
运行 main 方法,结果如下:
开始新增人员信息
新增通讯录人员信息成功
--------------
开始读取人员信息
七七的通讯录:
编号:1 姓名:韩信
号码类型 号码
MOBILE 17500001111
WORK 18900002222
--------------
结果可以正常写入并读取出来,查看生成的address_book.txt
文件,内容如下:
七七的通讯录<韩信hanxin@proto.com"
17500001111"
18900002222