欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ProtocolBuffers教程

程序员文章站 2022-05-21 19:59:18
...

ProtocolBuffers是Google提出的一种二进制的数据交换格式,性能较平常的XML格式提高了不少.它独立于平台和语言,google提供了C++,Java和Python三种语言的实现,通过第三方扩展可以支持更多的语言平台.现在新版本为2.4.1,但是还只提供2.3.0的protoc编译器下载,新版本需要自行编译了.

一下通过Google提供的例子讲解:

1.编写proto文件

ProtocolBuffers是通过定义.Proto文件做为数据交换的接口.文件中写入需要交换的bean.如:

// See README.txt for information and build instructions.

package tutorial;

// 定义包名
option java_package = "com.example.tutorial";
// 定义类名
option java_outer_classname = "AddressBookProtos";

// 定义message类
message Person {
  required string name = 1;	// required 为必选参数,如果传值为空会抛出IOException
  required int32 id = 2;        // Unique ID number for this person. 
  optional string email = 3;    // optional 为可选参数.

  // 定义枚举类
  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {	// 子类
    required string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }

  repeated PhoneNumber phone = 4;	// repeated为可重复参数,通过List实习
}

// Our address book file is just one of these.
message AddressBook {
  repeated Person person = 1;
}

注意:等号不是赋值,而是给字段名分配唯一的数字标签,用于升级时的版本兼容性。

该例子定义了一个AddressBook类.Book类中有多个Person类.

ProtocolBuffers教程

具体内容详见http://code.google.com/intl/zh-CN/apis/protocolbuffers/docs/proto.html

2.编译proto文件生成相应语言.

使用protoc进行编译:

protoc -I=$SRC_DIR --java_out=$DST_DIR $SRC_DIR/addressbook.proto
其他语言输出使用方法:

protoc --java_out . --cpp_out . --python_out . search_response_protos.proto
编译后生成com/example/tutorial/AddressBookProtos.java的引用类

3.使用proto

分析examples中的AddPerson.java

// See README.txt for information and build instructions.

import com.example.tutorial.AddressBookProtos.AddressBook;
import com.example.tutorial.AddressBookProtos.Person;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.PrintStream;

class AddPerson {
  // This function fills in a Person message based on user input.
  static Person PromptForAddress(BufferedReader stdin,
                                PrintStream stdout) throws IOException {
    // 构建Builder;类似于StringBuffer的类.
    Person.Builder person = Person.newBuilder();

    stdout.print("Enter person ID: ");
    person.setId(Integer.valueOf(stdin.readLine()));

    stdout.print("Enter name: ");
    person.setName(stdin.readLine());

    stdout.print("Enter email address (blank for none): ");
    String email = stdin.readLine();
    if (email.length() > 0) {
      person.setEmail(email);
    }

    while (true) {
      stdout.print("Enter a phone number (or leave blank to finish): ");
      String number = stdin.readLine();
      if (number.length() == 0) {
        break;
      }

      Person.PhoneNumber.Builder phoneNumber =
        Person.PhoneNumber.newBuilder().setNumber(number);

      stdout.print("Is this a mobile, home, or work phone? ");
      String type = stdin.readLine();
      if (type.equals("mobile")) {
        phoneNumber.setType(Person.PhoneType.MOBILE);
      } else if (type.equals("home")) {
        phoneNumber.setType(Person.PhoneType.HOME);
      } else if (type.equals("work")) {
        phoneNumber.setType(Person.PhoneType.WORK);
      } else {
        stdout.println("Unknown phone type.  Using default.");
      }

      person.addPhone(phoneNumber);
    }
    // 通过Builder构建返回Message
    return person.build();
  }

  // Main function:  Reads the entire address book from a file,
  //   adds one person based on user input, then writes it back out to the same
  //   file.
  public static void main(String[] args) throws Exception {
    if (args.length != 1) {
      System.err.println("Usage:  AddPerson ADDRESS_BOOK_FILE");
      System.exit(-1);
    }
    
    // 创建AddressBook Builder.
    AddressBook.Builder addressBook = AddressBook.newBuilder();

    // Read the existing address book.
    try {
      FileInputStream input = new FileInputStream(args[0]);
      addressBook.mergeFrom(input);
      input.close();
    } catch (FileNotFoundException e) {
      System.out.println(args[0] + ": File not found.  Creating a new file.");
    }

    // Add an address.
    addressBook.addPerson(
      PromptForAddress(new BufferedReader(new InputStreamReader(System.in)),
                       System.out));

    // Write the new address book back to disk.
    FileOutputStream output = new FileOutputStream(args[0]);
    addressBook.build().writeTo(output);
    output.close();
  }
}
参见:http://code.google.com/intl/zh-CN/apis/protocolbuffers/docs/reference/java-generated.html

执行:

javac -d . -classpath .;protobuf-java-2.4.1.jar AddPerson.java ListPeople.java com\example\tutorial\AddressBookProtos.java

报错:

ProtocolBuffers教程

查看AddressBookProtos.java发现2.4.1中GeneratedMessage提供了一个新的空方法需要实现,覆盖该空方法.

重新编译成功,生成class类.

4. 测试

利用接口调用AddPerson添加Person.

java -cp .;protobuf-java-2.4.1.jar AddPerson addr.dat
ProtocolBuffers教程
利用接口调用ListPeople查找添加的Person.

java -cp .;protobuf-java-2.4.1.jar ListPeople addr.dat
ProtocolBuffers教程

5.参考资料

Google的教程

二进制编码格式

关于ProtocolBuffers

Google Protocol Buffer 的使用和原理

protobuf和thrift的对比