编译proto文件
上一篇,介绍了proto文件,以及用idea的工具编译了proto文件。当然,我们也可以直接用protoc命令来编译。
protoc -I=SRC_DIR --java_out=DST_DIR SRC_DIR/hello.proto
- protoc需要定位到protoc.exe目录,要么进入
F:\soft\protoc-3.10.1-win64\bin
的目录(以自己的环境为准),要么配置在系统环境变量path里。 -
-I=IMPORT_PATH
写法同--proto_path=IMPORT_PATH
,用来指定proto文件目录, -
--java_out=
指定生成的java文件存放的目录,java的类名同proto文件名,但是如果Message的名称和proto名称一样,比如上一篇的简单例子,proto文件名是Person.proto,Message也是Person,那类名就是PersonOutClass。如果是proto文件名是foo_bar.proto,那类名就是FooBar。这边要注意的是,文件夹是要存在的,protoc不会帮我们创建。
java文件
proto文件
syntax = "proto3";
package ch13;
option java_package = "com.example.ch13";
option java_outer_classname = "AddressBookProtos";
message Person {
string name = 1;
int32 id = 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 {
repeated Person person = 1;
}
生成java文件AddressBookProtos.java后,我们看看java类里有哪些内容。
PersonOrBuilder
PersonOrBuilder继承了com.google.protobuf.MessageOrBuilder
,我们看看这个接口的几个方法,都是对应我们在proto文件中定义的字段,很像我们的javaBean,但是没有set方法,有get方法。
对于Repeated字段,还提供了其他的方法,比如通过索引查找、获取个数等。
// 对应着name
java.lang.String getName();
com.google.protobuf.ByteString getNameBytes();
// 对应着id
int getId();
// 对应着email
java.lang.String getEmail();
com.google.protobuf.ByteString getEmailBytes();
// 对应着phones
java.util.List<com.example.ch13.AddressBookProtos.Person.PhoneNumber> getPhonesList();
com.example.ch13.AddressBookProtos.Person.PhoneNumber getPhones(int index);
int getPhonesCount();
java.util.List<? extends com.example.ch13.AddressBookProtos.Person.PhoneNumberOrBuilder> getPhonesOrBuilderList();
com.example.ch13.AddressBookProtos.Person.PhoneNumberOrBuilder getPhonesOrBuilder(int index);
Person
Person继承了com.google.protobuf.GeneratedMessageV3,还实现了上面的PersonOrBuilder接口。
Person类中定义了一个枚举PhoneType:
Message中嵌套了PhoneNumber,所以Person中包含了PhoneNumberOrBuilder和PhoneNumber,这两个结构同PersonOrBuilder和Person:
Person类中还包含了重要的Builder,这个后面在详细说。
除了上面几个枚举、接口、类,还包含了几个方法:getDefaultInstance
:返回Person的单例。等同于Person.newBuilder().build()
public static com.example.ch13.AddressBookProtos.Person getDefaultInstance() {
return DEFAULT_INSTANCE;
}
parseFrom(...)
:解析给定的数据源,转成Message对象的Person。newBuilder
:创建一个build
Builder
Builder继承了com.google.protobuf.GeneratedMessageV3.Builder<Builder>
,还实现了PersonOrBuilder接口。
主要有构建类,对字段的set、get、clear等操作。
实践
写
先获取Builder,然后对各个实例进行set或者add操作,最后build返回一个AddressBook,通过AddressBook的writeTo方法,把序列号的值写入文件。
AddPerson
class AddPerson {
public static void main(String[] args) throws Exception {
AddressBook.Builder builder =AddressBook.newBuilder().addPerson(Person.newBuilder().setName("aa")
.setId(1)
.setEmail("123@qq.com")
.addPhones(Person.PhoneNumber.newBuilder()
.setNumber("111")
.setType(Person.PhoneType.HOME))
.addPhones(Person.PhoneNumber.newBuilder()
.setNumber("222")
.setType(Person.PhoneType.MOBILE))).addPerson(Person.newBuilder().setName("bb")
.setId(2)
.setEmail("456@qq.com")
.addPhones(Person.PhoneNumber.newBuilder()
.setNumber("333")
.setType(Person.PhoneType.HOME))
.addPhones(Person.PhoneNumber.newBuilder()
.setNumber("444")
.setType(Person.PhoneType.MOBILE)));
AddressBook addressBook = builder.build();
PersonList.Print(addressBook);
addressBook.writeTo(new FileOutputStream("f:\\1.txt"));
}
}
PersonList
class PersonList {
static void Print(AddressBook addressBook) {
for (Person person: addressBook.getPersonList()) {
System.out.println("Person ID: " + person.getId());
System.out.println(" Name: " + person.getName());
System.out.println(" E-mail address: " + person.getEmail());
for (Person.PhoneNumber phoneNumber : person.getPhonesList()) {
switch (phoneNumber.getType()) {
case MOBILE:
System.out.print(" Mobile phone #: ");
break;
case HOME:
System.out.print(" Home phone #: ");
break;
case WORK:
System.out.print(" Work phone #: ");
break;
}
System.out.println(phoneNumber.getNumber());
}
}
}
}
运行结果:
读
ListPeople,通过parseFrom读取
class ListPeople {
public static void main(String[] args) throws Exception {
AddressBook addressBook =
AddressBook.parseFrom(new FileInputStream("f:\\1.txt"));
PersonList.Print(addressBook);
}
}
运行结果同上。
合并
public class MergePerson {
public static void main(String[] args) {
Person person1 =Person.newBuilder().setId(1).addPhones(Person.PhoneNumber.newBuilder().setNumber("111").setType(Person.PhoneType.MOBILE)).build();
Person person2 =Person.newBuilder().setId(2).addPhones(Person.PhoneNumber.newBuilder().setNumber("222").setType(Person.PhoneType.WORK)).build();
person1 = person1.toBuilder().mergeFrom(person2).build();
System.out.println("Person ID: " + person1.getId());
for (Person.PhoneNumber phoneNumber : person1.getPhonesList()) {
switch (phoneNumber.getType()) {
case MOBILE:
System.out.print(" Mobile phone #: ");
break;
case HOME:
System.out.print(" Home phone #: ");
break;
case WORK:
System.out.print(" Work phone #: ");
break;
}
System.out.println(phoneNumber.getNumber());
}
}
}
运行结果如下:
可以看出id被后面的覆盖了,而PhoneNumber是累加的
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。