Java大猿帥成長手冊, GitHub JavaEgg ,N線互聯網開發必備技能兵器譜
Google Protocol Buffer( 簡稱 Protobuf) 是 Google 公司內部的混合語言數據標準 ,是一種輕便高效的結構化數據存儲格式,能夠用於結構化數據串行化,或者說序列化(將 數據結構或對象 轉換成 二進制串 的過程 )。它很適合作數據存儲或 RPC 數據交換格式。可用於通信協議、數據存儲等領域的語言無關、平臺無關、可擴展的序列化結構數據格式 java
protocol buffers 誕生之初是爲了解決服務器端新舊協議(高低版本)兼容性問題,名字也很體貼,「協議緩衝區」。只不事後期慢慢發展成用於傳輸數據。git
筆者所在的360廣告投放,N億條商品信息的數據所有采用PB格式存儲、傳輸。github
在傳輸數據量大、網絡環境不穩定的數據存儲和RPC數據交換場景比較合適數組
官網 Protocol Buffer Basics: Java https://developers.google.com...服務器
.proto
文件的消息格式(你但願存儲的數據格式描述文件)syntax = "proto2"; package tutorial; option java_package = "com.example.tutorial"; 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; }
☆☆☆注:網絡
.proto
項目間命名 發生衝突bool
, int32
, float
, double
, string
,enum
... )字段的集合,在一個.proto文件中能夠定義多個message,一個message裏也能夠定義另一個message(至關於java的類,固然也能夠有內部類)import
的,import "xxx.proto";
像每一個字段也必須有修飾符,PB提供的字段修飾符有3種數據結構
標識號:經過二進制格式惟一標識每一個字段 ,使用後就不可以再改變ide
Protobuf
協議實現中對這些標識號進行了預留。倘若使用,則會報錯每一個字段在進行編碼時都會佔用內存,而 佔用內存大小 取決於 標識號:工具
執行:protoc -I=源地址 --java_out=目標地址 源地址/xxx.proto 優化
E:learningprotoc-3.9.0-win64bin>protoc.exe -I=E:learning --java_out=E:lear
ning E:learningaddressbook.proto
實際使用中:
protoc.exe -I=E:learn-workspacestarfishstarfish-learnsrcmainjavaprivstarfishProtocolBuffersproto --java_out=E:learn-workspacestarfishstarfish-learnsrcmainjava E:learn-workspacestarfishstarfish-learnsrcmainjavaprivstarfishProtocolBuffersprotoaddressbook.proto)
package priv.starfish.ProtocolBuffers; import com.google.protobuf.InvalidProtocolBufferException; import priv.starfish.ProtocolBuffers.AddressBookProtos.Person; import priv.starfish.ProtocolBuffers.AddressBookProtos.AddressBook; import java.util.Arrays; /** * @author: starfish * @date: 2019/7/24 14:39 * @description: */ public class HelloProto { public static void main(String[] args) { Person person = Person.newBuilder() .setId(123) .setName("starfish") .setEmail("starfish@126.cn") .addPhones(AddressBookProtos.Person.PhoneNumber.newBuilder() .setType(AddressBookProtos.Person.PhoneType.HOME) .setNumber("13555555555") .build()) .build(); System.out.println(person.toString()); System.out.println(person.isInitialized()); try { //序列化和反序列化 System.out.println(Arrays.toString(person.toByteArray())); System.out.println(person.toByteString()); Person newPerson = Person.parseFrom(person.toByteArray()); System.out.println(newPerson); newPerson = Person.parseFrom(person.toByteString()); System.out.println(newPerson); } catch (InvalidProtocolBufferException e) { e.printStackTrace(); } // 向地址簿添加兩條Person信息 AddressBook.Builder books = AddressBook.newBuilder(); books.addPeople(person); books.addPeople(Person.newBuilder(person).setEmail("xin@163.com") .build()); System.out.println("AddressBook對象信息:"); System.out.println(books.build()); } }
編譯後生成的java類是不可變的,相似java的String,不可修改
構造消息,必須先構造一個builder,而後set屬性(能夠一連串的set),最後調用build() 方法。
PB經常使用方法
isInitialized()
: 檢查必填字段(required)是否有set值toString()
: 返回message的可讀字符串格式mergeFrom(Message other)
: 合併messageclear()
: 清空字段值byte[] toByteArray();
: 序列化message,返回字節數組 MessageType parseFrom(byte[] data);
: 解析給定的字節數組void writeTo(OutputStream output);
: 序列化message並寫入輸出流OutputStream
.MessageType parseFrom(InputStream input);
: 從輸入流 InputStream
讀取並解析messageReference: