ProtoBuf初体验

ProtoBuf初体验

ProtoBuf介绍

定义

protocol buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等。

与XML和JSON对比

1.序列化后体积相比Json和XML很小,适合网络传输

2.支持跨平台多语言

3.消息格式升级和兼容性还不错

4.序列化反序列化速度很快,快于Json的处理速度快

特点

1.语言无关、平台无关。即 ProtoBuf 支持 Java、C++、Python 等多种
语言,支持多个平台
2.高效。
3.扩展性、兼容性好。你可以更新数据结构,而不影响和破坏原有的旧程

.proto 文件

定义

使用 proto语法编写的文本文件, 用来定义数据格式。

作用

当你使用protobuf编译器编译一个.proto文件,它会生成在.proto内你描述的消息类型的操作代码,这些代码是根据你所选择的编程功能语言决定的。这些操作代码内包含了设置字段值和读取字段值,以及序列化到输出流和从输入流反序列化。

示例

addressbook.proto

// See README.txt for information and build instructions.
//
// Note: START and END tags are used in comments to define sections used in
// tutorials.  They are not part of the syntax for Protocol Buffers.
//
// To get an in-depth walkthrough of this file and the related examples, see:
// https://developers.google.com/protocol-buffers/docs/tutorials

// [START declaration]
syntax = "proto3";
package tutorial;

import "google/protobuf/timestamp.proto";
// [END declaration]

// [START java_declaration]
option java_package = "com.example.tutorial";
option java_outer_classname = "AddressBookProtos";
// [END java_declaration]

// [START csharp_declaration]
option csharp_namespace = "Google.Protobuf.Examples.AddressBook";
// [END csharp_declaration]

// [START messages]
message Person {
  string name = 1;
  int32 id = 2;  // Unique ID number for this person.
  string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    string number = 1;
    PhoneType type = 2;
  }

  repeated PhoneNumber phones = 4;

  google.protobuf.Timestamp last_updated = 5;
}

// Our address book file is just one of these.
message AddressBook {
  repeated Person people = 1;
}
// [END messages]

protobuf 编译器(compile)

作用

将 proto 文件编译成不同语言的实现, 这样不同语言中的数据就可以用 protobuf 格式的数据进行交互。

不同语言编译后说明

C++:编译器会按照每个.proto文件生成与其对应的.h和.cc文件,每个消息类似 都有独立的消息操作类。
Java:编译器将会生成一个.java文件和一个操作类,此操作类为所有消息类型所共有, 使用一个特别的Builder类为每个消息类型实例化。
Python:有一点不同 – 编译器会为每个消息生成一个模块每个模块有一个静态描述符, 该模块与一个元类在运行时创建一个所需数据操作类。

Java举例

protoc.exe --java_out=./ addressbook.proto

生成AddressBookProtos.java文件和对应的目录结构:

protobuf 运行时(runtime)

作用

protobuf 运行时所需要的库,包括生成代码中依赖的库和操作生成代码的库。

Java运行时依赖

<!--If you are using Maven, use the following:-->

<dependency>
  <groupId>com.google.protobuf</groupId>
  <artifactId>protobuf-java</artifactId>
  <version>3.11.0</version>
</dependency>

<!--
Make sure the version number of the runtime matches (or is newer than) the version number of the protoc.
If you want to use features like protobuf JsonFormat, add a dependency on the protobuf-java-util package:
-->
<dependency>
  <groupId>com.google.protobuf</groupId>
  <artifactId>protobuf-java-util</artifactId>
  <version>3.11.0</version>
</dependency>

Java使用ProtoBuf生成代码

class AddPerson {
    // This function fills in a Person message based on user input.
    static Person PromptForAddress(BufferedReader stdin,
                                   PrintStream stdout) throws IOException {
        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.addPhones(phoneNumber);
        }

        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 {
       String  addressBookPath="./address_book";
        AddressBook.Builder addressBook = AddressBook.newBuilder();

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

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

        // Write the new address book back to disk.
        FileOutputStream output = new FileOutputStream(addressBookPath);
        try {
            addressBook.build().writeTo(output);
        } finally {
            output.close();
        }*/
    }
}
原文地址:https://www.cnblogs.com/yanshaoshuai/p/12125486.html