官網:https://github.com/google/protobuf
環境:windows,java
1. protobuf概述
protobuf是Google開發一種數據描述格式,能夠將結構化數據序列化,可用於數據存儲,通信協議等方面。
protobuf是以二進制來存儲數據的。相對於JSON和XML具有以下優點:
- 簡潔
- 體積小:消息大小只需要XML的1/10 ~ 1/3
- 速度快:解析速度比XML快20 ~ 100倍
- 使用protobuf的編譯器,可以生成更容易在編程中使用的數據訪問代碼
- 更好的兼容性,protobuf設計的一個原則就是要能夠很好的支持向下或向上兼容
2. 下載,安裝
在使用protobuf之前,需要安裝protobuf編譯器和運行時環境。
由於protobuf是跨平台,跨語言的,所以需要下載和安裝對應版本的編譯器和運行時依賴。
(1)protobuf編譯器下載:https://github.com/google/protobuf/releases。
對於windows平台,下載:protoc-${version}-win32.zip。在此以protoc-3.3.0-win32.zip為例。
解壓到指定目錄,如:D:\protoc-3.3.0-win32。添加到windows環境變量:D:\protoc-3.3.0-win32\bin。
(2)protobuf運行時下載:protobuf運行時環境是區分不同語言的,針對不同語言的安裝方式不同。
下載protobuf到指定目錄:git clone https://github.com/google/protobuf.git,如:D:\protobuf。
對於java語言而言,可以通過maven將protobuf運行時依賴安裝到本地倉庫,詳見:https://github.com/google/protobuf/tree/master/java。
需要注意的是,在執行:mvn install 之前,需要將protobuf編譯器(在此即:D:\protoc-3.3.0-win32\bin\protoc.exe)拷貝到protobuf目錄下的src路徑下,即:D:\protobuf\src。
否則,在編譯安裝protobuf運行時環境時報錯:
Execute failed: java.io.IOException: Cannot run program ...
cd D:\protobuf\java
mvn install(如果不想執行單元測試,可以執行:mvn install -Dmaven.test.skip=true)
將在maven本地倉庫安裝protobuf運行時依賴jar包(注意:下載protobuf編譯器和運行時環境的版本要保持一致!在此下載的是最新版本:3.3.0),包括:
- protobuf-java: The core Java Protocol Buffers library. Most users only need this artifact.
- protobuf-lite: The lite version of core Java Protobuf Buffers library. It is a subset of the core library and is used together with the 'lite' code generator flag to reduce generated code size for mobile.
- protobuf-java-util: Utilities to work with protos. It contains JSON support as well as utilities to work with proto3 well-known types.
3. 使用protobuf
新建一個空的maven項目,並添加protobuf運行時依賴:
pom.xml:
<dependencies> <!-- 添加protobuf運行時依賴 --> <dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> <version>3.3.0</version> </dependency> </dependencies>
(1)新建protobuf數據描述文件:addressbook.proto
syntax = "proto2"; package tutorial; option java_package = "org.chench.test.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 phones = 4; } message AddressBook { repeated Person people = 1; }
編譯addressbook.proto,在windows控制台進入addressbook.proto文件所在目錄路徑下,執行如下編譯操作:
protoc -I=. --java_out=. ./addressbook.proto
生成java class:org.chench.test.protobuf.AddressBookProtos.java,將生成的java文件拷貝到前面新建的maven項目中。
(2)保存protobuf序列化數據到文件
package org.chench.test.protobuf; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import org.chench.test.protobuf.AddressBookProtos.AddressBook; import org.chench.test.protobuf.AddressBookProtos.Person; import org.chench.test.protobuf.AddressBookProtos.Person.PhoneNumber; import org.chench.test.protobuf.AddressBookProtos.Person.PhoneType; /** * 使用protobuf類示例: <br /> * 從控制台輸入相關信息,然后將數據序列化到文件。 * @desc org.chench.test.protobuf.AddPerson * @author chench9@lenovo.com * @date 2017年6月7日 */ public class AddPerson { 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; } PhoneNumber.Builder phoneNumber = PhoneNumber.newBuilder(); phoneNumber.setNumber(number); stdout.print("Is this a mobile, home, or work phone? "); String type = stdin.readLine(); if("mobile".equalsIgnoreCase(type)) { phoneNumber.setType(PhoneType.MOBILE); }else if("home".equalsIgnoreCase(type)) { phoneNumber.setType(PhoneType.HOME); }else if("work".equalsIgnoreCase(type)) { phoneNumber.setType(PhoneType.WORK); } person.addPhones(phoneNumber); } return person.build(); } /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { if (args.length != 1) { System.err.println("Usage: AddPerson ADDRESS_BOOK_FILE"); System.exit(-1); } AddressBook.Builder addressBook = AddressBook.newBuilder(); try { // 從指定文件讀取數據 addressBook.mergeFrom(new FileInputStream(args[0])); } catch (FileNotFoundException e) { System.out.println(args[0] + ": File not found. Creating a new file."); e.printStackTrace(); } addressBook.addPeople(PromptForAddress(new BufferedReader(new InputStreamReader(System.in)), System.out)); FileOutputStream out = new FileOutputStream(args[0]); addressBook.build().writeTo(out); } }
(3)從protobuf序列化文件中讀取之前保存進去的數據。
package org.chench.test.protobuf; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import org.chench.test.protobuf.AddressBookProtos.AddressBook; import org.chench.test.protobuf.AddressBookProtos.Person; import org.chench.test.protobuf.AddressBookProtos.Person.PhoneNumber; /** * 從protobuf序列化文件讀取數據。 * @desc org.chench.test.protobuf.ListPeople * @author chench9@lenovo.com * @date 2017年6月7日 */ public class ListPeople { static void Print(AddressBook addressBook) { for(Person p : addressBook.getPeopleList()) { System.out.println("Person ID: " + p.getId()); System.out.println(" Name: " + p.getName()); if (p.hasEmail()) { System.out.println(" E-mail address: " + p.getEmail()); } for(PhoneNumber pn : p.getPhonesList()) { switch (pn.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(pn.getNumber()); } } } /** * @param args * @throws IOException * @throws FileNotFoundException */ public static void main(String[] args) throws IOException { if (args.length != 1) { System.err.println("Usage: ListPeople ADDRESS_BOOK_FILE"); System.exit(-1); } try { AddressBook addressBook = AddressBook.parseFrom(new FileInputStream(args[0])); Print(addressBook); } catch (FileNotFoundException e) { System.out.println(args[0] + ": File not exists"); e.printStackTrace(); } } }
完畢!示例代碼詳見:https://git.oschina.net/cchanghui/test-protobuf.git
【參考】
http://www.iloveandroid.net/2015/10/08/studyPtorobuf/ protobuf簡單使用
https://developers.google.com/protocol-buffers/docs/javatutorial protobuf官方手冊