一个简单的Google Protocol Buffers基于Java语言示例

2015-09-17 00:00:00   作者:MangoCool   来源:MangoCool

Protocol Buffers (简称Protobuf)是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前提供了 C++、Java、Python 三种语言的 API。本文是以java语言为编码的示例。

软件:protoc-2.6.1

依赖:jdk1.7

开发环境:ideaIU-14.1.4

测试环境:win7

protoc-2.6.1下载地址:https://github.com/google/protobuf/releases/download/v2.6.1/protoc-2.6.1-win32.zip

建立maven工程ProtobufDemo,在pom.xml配置文件添加必要的依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>ProtobufDemo</groupId>
    <artifactId>ProtobufDemo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>

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

    </dependencies>

</project>

根据 Protobuf 的语法规范编写脚本文件 addressbook.proto:

option java_package = "com.mangocool.protobuf";
option java_outer_classname = "AddressBookProtos";

message Person {
  required string name = 1;
  required int32 id = 2;
  optional string email = 3;

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

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

  repeated PhoneNumber phone = 4;
}

message AddressBook {
  repeated Person person = 1;
}

java_package:生成proto文件的包路径。

java_outer_classname:生成proto文件的名字。

message:可以看作是Java语言中的javaBean。

option:可选项。

required:必选项。

repeated:可重复项。

通过Protobuf编译工具生成对应proto文件:

protoc -I=$资源路径 --java_out=$生成proto文件路径 $资源路径/addressbook.proto
我的命令:
protoc.exe -I=D:\ProtobufDemo\src\main\resources --java_out=D:\ProtobufDemo\src\main\java D:\ProtobufDemo\src\main\resources\addressbook.proto

编译生成的AddressBookProtos.java,这里就不贴了。

接下来我们将Person数据写入磁盘,并从磁盘读出。在classpath下新建文本文件addressbook.txt,用于写入Person和从中读取Person。

写入类WritePerson.java:

package com.mangocool.protobuf;

/**
 * Created by MANGOCOOL on 2015/9/16.
 */
import com.mangocool.protobuf.AddressBookProtos.AddressBook;
import com.mangocool.protobuf.AddressBookProtos.Person;

import java.io.*;

class WritePerson {

    static String path = "addressbook.txt";

    // 通过用户的输入来添加Person
    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.addPhone(phoneNumber);
        }

        return person.build();
    }

    // 读取本地文件addressBook,添加person,最终再写入本地文件addressBook
    public static void main(String[] args) throws Exception {

        AddressBook.Builder addressBook = AddressBook.newBuilder();

        File file = new File(path);

        // 读取本地存在的addressBook
        try {
            addressBook.mergeFrom(new FileInputStream(file));
        } catch (FileNotFoundException e) {
            System.out.println(args[0] + ": File not found.  Creating a new file.");
        }

        // 手动添加
        addressBook.addPerson(
                PromptForAddress(new BufferedReader(new InputStreamReader(System.in)),
                        System.out));
        // 程序添加
        Person.PhoneNumber.Builder phoneNum =
                Person.PhoneNumber.newBuilder().setNumber("22222222").setType(Person.PhoneType.WORK);
        Person.Builder person =
                Person.newBuilder().setName("李四").setId(002).setEmail("002@qq.com").addPhone(phoneNum);
        addressBook.addPerson(person);

        // 写入本地文件
        FileOutputStream output = new FileOutputStream(file);
        addressBook.build().writeTo(output);
        output.close();
    }
}
读取类ReadPerson.java:
package com.mangocool.protobuf;

/**
 * Created by MANGOCOOL on 2015/9/16.
 */
import com.mangocool.protobuf.AddressBookProtos.AddressBook;
import com.mangocool.protobuf.AddressBookProtos.Person;

import java.io.File;
import java.io.FileInputStream;

class ReadPerson {

    static String path = "addressbook.txt";

    // 遍历AddressBook中的所有的person并打印
    static void Print(AddressBook addressBook) {
        for (Person person: addressBook.getPersonList()) {
            System.out.println("Person ID: " + person.getId());
            System.out.println("  Name: " + person.getName());
            if (person.hasEmail()) {
                System.out.println("  E-mail address: " + person.getEmail());
            }

            for (Person.PhoneNumber phoneNumber : person.getPhoneList()) {
                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());
            }
        }
    }

    public static void main(String[] args) throws Exception {

        File file = new File(path);
        // 读取本地文件
        AddressBook addressBook = AddressBook.parseFrom(new FileInputStream(file));
        // 打印
        Print(addressBook);
    }
}
代码准备就绪,运行试试:

运行WritePerson.java,并根据提示输入,控制台显示:

Enter person ID: 001
Enter name: 张三
Enter email address (blank for none): 001@qq.com
Enter a phone number (or leave blank to finish): 11111111
Is this a mobile, home, or work phone? mobile
Enter a phone number (or leave blank to finish): 
运行ReadPerson.java,读取addressbook.txt中由WritePerson写入的信息:
Person ID: 1
  Name: 张三
  E-mail address: 001@qq.com
  Mobile phone #: 11111111
Person ID: 2
  Name: 李四
  E-mail address: 002@qq.com
  Work phone #: 22222222

本文对于数据只做了简单的处理,从本地文件做读取,旨意在了解和入门Protobuf。

需结合其他业务稍加修改即可,如将磁盘替换成网络socket,就可以实现基于网络的数据交换任务了。

到此本文就已结束,有不对或是不完善地方请多多指正以及多多谅解!


参考文章:https://developers.google.com/protocol-buffers/docs/javatutorial

标签: Google Protobuf Java 数据格式 Demo

分享:

上一篇JS计算宝宝出生后的年龄,两种表示方式,精确到秒哦

下一篇阻塞、非阻塞与同步、异步的区别,看过之后一定能懂

关于我

一个喜欢唱歌,热衷旅行,爱好电子产品的码农。没事,跟三五好友吼上几嗓子,约上几个背着行囊去露营或者宅在家里抱着孩子敲代码。

座右铭:当你的才华还撑不起你的野心的时候,你就应该静下心来学习,永不止步!

            人生之旅历途甚长,所争决不在一年半月,万不可因此着急失望,招精神之萎葸。


Copyright 芒果酷(mangocool.com) All rights reserved. 湘ICP备14019394号

免责声明:本网站部分文章转载其他媒体,意在为公众提供免费服务。如有信息侵犯了您的权益,可与本网站联系,本网站将尽快予以撤除。