protobuf那些事(二)

編譯proto文件

上一篇,介紹了proto文件,以及用idea的工具編譯了proto文件。固然,咱們也能夠直接用protoc命令來編譯。java

protoc -I=SRC_DIR --java_out=DST_DIR SRC_DIR/hello.proto
  1. protoc須要定位到protoc.exe目錄,要麼進入F:\soft\protoc-3.10.1-win64\bin的目錄(以本身的環境爲準),要麼配置在系統環境變量path裏。
  2. -I=IMPORT_PATH寫法同--proto_path=IMPORT_PATH,用來指定proto文件目錄,
  3. --java_out=指定生成的java文件存放的目錄,java的類名同proto文件名,可是若是Message的名稱和proto名稱同樣,好比上一篇的簡單例子,proto文件名是Person.proto,Message也是Person,那類名就是PersonOutClass。若是是proto文件名是foo_bar.proto,那類名就是FooBar。這邊要注意的是,文件夾是要存在的,protoc不會幫咱們建立。

java文件

proto文件segmentfault

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類裏有哪些內容。ide

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:
image.png
Message中嵌套了PhoneNumber,因此Person中包含了PhoneNumberOrBuilder和PhoneNumber,這兩個結構同PersonOrBuilder和Person:
image.png
Person類中還包含了重要的Builder,這個後面在詳細說。
image.png
除了上面幾個枚舉、接口、類,還包含了幾個方法:
getDefaultInstance:返回Person的單例。等同於Person.newBuilder().build()ui

public static com.example.ch13.AddressBookProtos.Person getDefaultInstance() {
  return DEFAULT_INSTANCE;
}

parseFrom(...):解析給定的數據源,轉成Message對象的Person。
newBuilder:建立一個buildgoogle

Builder

Builder繼承了com.google.protobuf.GeneratedMessageV3.Builder<Builder>,還實現了PersonOrBuilder接口。
主要有構建類,對字段的set、get、clear等操做。idea

實踐

先獲取Builder,而後對各個實例進行set或者add操做,最後build返回一個AddressBook,經過AddressBook的writeTo方法,把序列號的值寫入文件。
AddPersonspa

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"));
    }
}

PersonList3d

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());
            }
        }
    }
}

運行結果:
image.pngcode

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());
        }
    }
}

運行結果以下:
image.png能夠看出id被後面的覆蓋了,而PhoneNumber是累加的

相關文章
相關標籤/搜索