Protocol Buffer是Google的語言中立的,平臺中立的,可擴展機制的,用於序列化結構化數據 - 對比XML,但更小,更快,更簡單。您能夠定義數據的結構化,而後可使用特殊生成的源代碼輕鬆地在各類數據流中使用各類語言編寫和讀取結構化數據。php
先來看一個很是簡單的例子。假設你想定義一個「搜索請求」的消息格式,每個請求含有一個查詢字符串、你感興趣的查詢結果所在的頁數,以及每一頁多少條查詢結果。能夠採用以下的方式來定義消息類型的.proto文件了:html
syntax = "proto3";
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
}
複製代碼
proto3
語法:若是您不這樣作,protobuf 編譯器將假定您正在使用proto2。這必須是文件的第一個非空的非註釋行。SearchRequest
消息定義指定了三個字段(名稱/值對),一個用於要在此類型的消息中包含的每一個數據片斷。每一個字段都有一個名稱和類型。在上面的示例中,全部字段都是標量類型:兩個整數(page_number
和result_per_page
)和一個字符串(query
)。可是,您還能夠爲字段指定合成類型,包括枚舉和其餘消息類型。java
正如上述文件格式,在消息定義中,每一個字段都有惟一的一個數字標識符。這些標識符是用來在消息的二進制格式中識別各個字段的,一旦開始使用就不可以再改變。注:[1,15]以內的標識號在編碼的時候會佔用一個字節。[16,2047]以內的標識號則佔用2個字節。因此應該爲那些頻繁出現的消息元素保留 [1,15]以內的標識號。切記:要爲未來有可能添加的、頻繁出現的標識號預留一些標識號。python
最小的標識號能夠從1開始,最大到2^29 - 1, or 536,870,911。不可使用其中的[19000-19999]的標識號, Protobuf協議實現中對這些進行了預留。若是非要在.proto文件中使用這些預留標識號,編譯時就會報警。ios
消息字段能夠是如下之一:git
repeated
:此字段能夠在格式良好的消息中重複任意次數(包括零)。將保留重複值的順序。在proto3中,repeated
數字類型的字段默認使用packed
編碼。github
packed
您能夠在協議緩衝區編碼中找到有關編碼的更多信息。golang
能夠在單個.proto
文件中定義多種消息類型。若是要定義多個相關消息,這頗有用 - 例如,若是要定義與SearchResponse
消息類型對應的回覆消息格式,能夠將其添加到相同的消息.proto
:objective-c
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
}
message SearchResponse {
...
}
複製代碼
要爲.proto
文件添加註釋,請使用C / C ++ - 樣式//
和/* ... */
語法。json
/ * SearchRequest表示搜索查詢,帶有分頁選項
*代表響應中包含哪些結果。* /
message SearchRequest {
string query = 1;
int32 page_number = 2; //咱們想要哪一個頁碼?
int32 result_per_page = 3; //每頁返回的結果數。
}
複製代碼
若是經過徹底刪除字段或將其註釋來更新消息類型,則將來用戶能夠在對類型進行本身的更新時重用字段編號。若是之後加載相同的舊版本,這可能會致使嚴重問題.proto
,包括數據損壞,隱私錯誤等。確保不會發生這種狀況的一種方法是指定已刪除字段的字段編號(和/或名稱,這也可能致使JSON序列化問題)reserved
。若是未來的任何用戶嘗試使用這些字段標識符,協議緩衝編譯器將會抱怨。
message Foo {
reserved 2, 15, 9 to 11;
reserved "foo", "bar";
}
複製代碼
請注意,您不能在同一reserved
語句中混合字段名稱和字段編號。
.proto
?當您在a上運行協議緩衝區編譯器時.proto
,編譯器會生成您所選語言的代碼,您須要使用您在文件中描述的消息類型,包括獲取和設置字段值,將消息序列化爲輸出流,並從輸入流解析您的消息。
.h
和一個.cc
文件.proto
,併爲您文件中描述的每種消息類型提供一個類。.java
文件,其中包含每種消息類型的類,以及Builder
用於建立消息類實例的特殊類。.proto
而後與元類一塊兒使用,以在運行時建立必要的Python數據訪問類。.pb.go
文件中的每種消息類型生成一個類型的文件。.rb
包含消息類型的Ruby模塊的文件。pbobjc.h
和一個pbobjc.m
文件.proto
,其中包含文件中描述的每種消息類型的類。.cs
從每一個文件生成一個文件.proto
,其中包含文件中描述的每種消息類型的類。您能夠按照所選語言的教程(即將推出的proto3版本)瞭解有關爲每種語言使用API的更多信息。有關更多API詳細信息,請參閱相關API參考(proto3版本即將推出)。
標量消息字段能夠具備如下類型之一 - 該表顯示.proto
文件中指定的類型,以及自動生成的類中的相應類型:
.proto type | notes | C ++ type | Java type | Python type [2] | Type | Ruby type | C# type | PHP type |
---|---|---|---|---|---|---|---|---|
double | double | double | float | float64 | float | double | float | |
float | float | float | float | FLOAT32 | float | float | float | |
INT32 | 使用可變長度編碼。編碼負數的效率低 - 若是您的字段可能有負值,請改用sint32。 | INT32 | INT | INT | INT32 | Fixnum or Bignum (as needed) | INT | Integer |
Int64 | 使用可變長度編碼。編碼負數的效率低 - 若是您的字段可能有負值,請改用sint64。 | Int64 | long | int / long [3] | Int64 | TWINS | long | Integer/string[5] |
UINT32 | 使用可變長度編碼。 | UINT32 | int [1] | int / long [3] | UINT32 | Fixnum or Bignum (as needed) | UINT | Integer |
UINT64 | 使用可變長度編碼。 | UINT64 | Long [1] | int / long [3] | UINT64 | TWINS | ULONG | Integer/string[5] |
SINT32 | 使用可變長度編碼。簽名的int值。這些比常規int32更有效地編碼負數。 | INT32 | INT | INT | INT32 | Fixnum or Bignum (as needed) | INT | Integer |
sint64 | 使用可變長度編碼。簽名的int值。這些比常規int64更有效地編碼負數。 | Int64 | long | int / long [3] | Int64 | TWINS | long | Integer/string[5] |
fixed32 | 老是四個字節。若是值一般大於2 28,則比uint32更有效。 | UINT32 | int [1] | int / long [3] | UINT32 | Fixnum or Bignum (as needed) | UINT | Integer |
fixed64 | 老是八個字節。若是值一般大於2 56,則比uint64更有效。 | UINT64 | Long [1] | int / long [3] | UINT64 | TWINS | ULONG | Integer/string[5] |
sfixed32 | 老是四個字節。 | INT32 | INT | INT | INT32 | Fixnum or Bignum (as needed) | INT | Integer |
sfixed64 | 老是八個字節。 | Int64 | long | int / long [3] | Int64 | TWINS | long | Integer/string[5] |
Boolean | Boolean | Boolean | Boolean | Boolean | TrueClass / FalseClass | Boolean | Boolean | |
string | 字符串必須始終包含UTF-8編碼或7位ASCII文本。 | string | string | str / unicode[4] | string | String (UTF-8) | string | string |
byte | 能夠包含任意字節序列。 | string | Byte string | Strait | []byte | String (ASCII-8BIT) | Byte string | string |
在協議緩衝區編碼中序列化消息時,您能夠找到有關如何編碼這些類型的更多信息。
[1]在Java中,無符號的32位和64位整數使用它們的帶符號對應表示,最高位只是存儲在符號位中。
[2]在全部狀況下,將值設置爲字段將執行類型檢查以確保其有效。
[3] 64位或無符號32位整數在解碼時始終表示爲long,但若是在設置字段時給出int,則能夠爲int。在全部狀況下,該值必須適合設置時表示的類型。見[2]。
[4] Python字符串在解碼時表示爲unicode,但若是給出了ASCII字符串,則能夠是str(這可能會發生變化)。
[5] Integer用於64位計算機,字符串用於32位計算機。
解析消息時,若是編碼消息不包含特定的單數元素,則解析對象中的相應字段將設置爲該字段的默認值。這些默認值是特定於類型的:
重複字段的默認值爲空(一般是相應語言的空列表)。
請注意,對於標量消息字段,一旦解析了消息,就沒法肯定字段是否顯式設置爲默認值(例如,是否設置了布爾值false
)或者根本沒有設置:您應該記住這一點在定義消息類型時。例如,false
若是您不但願默認狀況下也發生這種行爲,那麼在設置爲時,沒有一個布爾值能夠啓用某些行爲。還要注意的是,若是一個標消息字段被設置爲默認值,該值將不會在電線上連載。
有關默認值如何在生成的代碼中工做的更多詳細信息,請參閱所選語言的生成代碼指南。
在定義消息類型時,您可能但願其中一個字段只有一個預約義的值列表。例如,假設你想添加一個 corpus
字段每一個SearchRequest
,其中語料庫能夠 UNIVERSAL
,WEB
,IMAGES
,LOCAL
,NEWS
,PRODUCTS
或VIDEO
。您能夠很是簡單地經過enum
爲每一個可能的值添加一個常量來定義消息定義。
在下面的示例中,咱們添加了一個帶有全部可能值的enum
調用Corpus
,以及一個類型的字段Corpus
:
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
enum Corpus {
UNIVERSAL = 0;
WEB = 1;
IMAGES = 2;
LOCAL = 3;
NEWS = 4;
PRODUCTS = 5;
VIDEO = 6;
}
Corpus corpus = 4;
}
複製代碼
如您所見,Corpus
枚舉的第一個常量映射爲零:每一個枚舉定義必須包含一個映射到零的常量做爲其第一個元素。這是由於:
您能夠經過爲不一樣的枚舉常量指定相同的值來定義別名。爲此,您須要將allow_alias
選項設置爲true
,不然協議編譯器將在找到別名時生成錯誤消息。
enum EnumAllowingAlias {
option allow_alias = true;
UNKNOWN = 0;
STARTED = 1;
RUNNING = 1;
}
enum EnumNotAllowingAlias {
UNKNOWN = 0;
STARTED = 1;
// RUNNING = 1; // Uncommenting this line will cause a compile error inside Google and a warning message outside.
}
複製代碼
枚舉器常量必須在32位整數範圍內。因爲enum
值在線上使用varint編碼,所以負值效率低,所以不建議使用。您能夠enum
在消息定義中定義s,如上例所示,enum
也能夠在外部定義 - 這些能夠在.proto
文件的任何消息定義中重用。您還可使用enum
語法將一個消息中聲明的類型用做另外一個消息中的字段類型。 *MessageType*.*EnumType*
當你在.proto
使用a的協議緩衝編譯器上運行時enum
,生成的代碼將具備enum
Java或C ++ 的相應代碼,這EnumDescriptor
是Python的一個特殊類,用於在運行時生成的類中建立一組帶有整數值的符號常量。
在反序列化期間,將在消息中保留沒法識別的枚舉值,可是當反序列化消息時,如何表示這種值取決於語言。在支持具備超出指定符號範圍的值的開放枚舉類型的語言中,例如C ++和Go,未知的枚舉值僅做爲其基礎整數表示存儲。在具備封閉枚舉類型(如Java)的語言中,枚舉中的大小寫用於表示沒法識別的值,而且可使用特殊訪問器訪問基礎整數。在任何一種狀況下,若是消息被序列化,則仍然會使用消息序列化沒法識別的值。
有關如何enum
在應用程序中使用消息的詳細信息,請參閱所選語言的生成代碼指南。
若是經過徹底刪除枚舉條目或將其註釋掉來更新枚舉類型,則將來用戶能夠在對類型進行本身的更新時重用該數值。若是之後加載相同的舊版本,這可能會致使嚴重問題.proto
,包括數據損壞,隱私錯誤等。確保不會發生這種狀況的一種方法是指定已刪除條目的數值(和/或名稱,這也可能致使JSON序列化問題)reserved
。若是未來的任何用戶嘗試使用這些標識符,協議緩衝編譯器將會抱怨。您可使用max
關鍵字指定保留的數值範圍達到最大可能值。
enum Foo {
reserved 2, 15, 9 to 11, 40 to max;
reserved "FOO", "BAR";
}
複製代碼
請注意,您不能在同一reserved
語句中混合字段名稱和數值。
您可使用其餘消息類型做爲字段類型。例如,假設你想包括Result
每一個消息的SearchResponse
消息-要作到這一點,你能夠定義一個Result
在同一個消息類型.proto
,而後指定類型的字段Result
中SearchResponse
:
message SearchResponse {
repeated Result results = 1;
}
message Result {
string url = 1;
string title = 2;
repeated string snippets = 3;
}
複製代碼
在上面的示例中,Result
消息類型在同一文件中定義SearchResponse
- 若是要用做字段類型的消息類型已在另外一個.proto
文件中定義,該怎麼辦?
您能夠.proto
經過導入來使用其餘文件中的定義。要導入其餘.proto
人的定義,請在文件頂部添加import語句:
import「myproject / other_protos.proto」;
複製代碼
默認狀況下,您只能使用直接導入.proto
文件中的定義。可是,有時您可能須要將.proto
文件移動到新位置。.proto
如今,您能夠.proto
在舊位置放置一個虛擬文件,以使用該import public
概念將全部導入轉發到新位置,而不是直接移動文件並在一次更改中更新全部調用站點。import public
任何導入包含該import public
語句的proto的人均可以傳遞依賴關係。例如:
// new.proto
// All definitions are moved here
複製代碼
// old.proto
//This is the proto that all clients are importing.
import public「new.proto」;
import「other.proto」;
複製代碼
// client.proto
import "old.proto";
//您使用old.proto和new.proto中的定義,但不使用other.proto
複製代碼
協議編譯器使用-I
/ --proto_path
flag 在協議編譯器命令行中指定的一組目錄中搜索導入的文件 。若是沒有給出標誌,它將查找調用編譯器的目錄。一般,您應該將--proto_path
標誌設置爲項目的根目錄,並對全部導入使用徹底限定名稱。
能夠導入proto2消息類型並在proto3消息中使用它們,反之亦然。可是,proto2枚舉不能直接用於proto3語法(若是導入的proto2消息使用它們就能夠了)。
您能夠在其餘消息類型中定義和使用消息類型,以下例所示 - 此處Result
消息在消息中定義SearchResponse
:
message SearchResponse {
message Result {
string url = 1;
string title = 2;
repeated string snippets = 3;
}
repeated Result results = 1;
}
複製代碼
若是要在其父消息類型以外重用此消息類型,請將其稱爲: *Parent*.*Type*
message SomeOtherMessage {
SearchResponse.Result result = 1;
}
複製代碼
您能夠根據須要深刻嵌套消息:
message Outer { // Level 0
message MiddleAA { // Level 1
message Inner { // Level 2
int64 ival = 1;
bool booly = 2;
}
}
message MiddleBB { // Level 1
message Inner { // Level 2
int32 ival = 1;
bool booly = 2;
}
}
}
複製代碼
若是現有的消息類型再也不知足您的全部需求 - 例如,您但願消息格式具備額外的字段 - 但您仍然但願使用使用舊格式建立的代碼,請不要擔憂!在不破壞任何現有代碼的狀況下更新消息類型很是簡單。請記住如下規則:
.proto
不會意外地重複使用該編號。int32
,uint32
,int64
,uint64
,和bool
都是兼容的-這意味着你能夠改變這些類型到另外一個的一個場不破壞forwards-或向後兼容。若是從導線中解析出一個不符合相應類型的數字,您將得到與在C ++中將該數字轉換爲該類型相同的效果(例如,若是將64位數字做爲int32讀取,它將被截斷爲32位)。sint32
而且sint64
彼此兼容但與其餘整數類型不兼容。string``bytes
只要字節是有效的UTF-8 ,它們是兼容的。bytes
若是字節包含消息的編碼版本,則嵌入消息是兼容的。fixed32
與兼容sfixed32
,並fixed64
用sfixed64
。enum
與兼容int32
,uint32
,int64
,和uint64
電線格式條款(注意,若是他們不適合的值將被截斷)。但請注意,在反序列化消息時,客戶端代碼可能會以不一樣方式對待它們:例如,enum
將在消息中保留未識別的proto3 類型,但在反序列化消息時如何表示這種類型取決於語言。Int字段老是保留它們的價值。oneof
是安全且二進制兼容的。oneof
若是您肯定沒有代碼一次設置多個字段,則將多個字段移動到新字段多是安全的。將任何字段移動到現有字段oneof
並不安全。未知字段是格式良好的協議緩衝區序列化數據,表示解析器沒法識別的字段。例如,當舊二進制文件解析具備新字段的新二進制文件發送的數據時,這些新字段將成爲舊二進制文件中的未知字段。
最初,proto3消息在解析期間老是丟棄未知字段,但在3.5版本中,咱們從新引入了保存未知字段以匹配proto2行爲。在版本3.5及更高版本中,未知字段在解析期間保留幷包含在序列化輸出中。
該Any
消息類型,可使用郵件做爲嵌入式類型,而沒必要本身.proto定義。一個Any
含有任意的序列化消息bytes
,以充當一個全局惟一標識符和解析到該消息的類型的URL一塊兒。要使用該Any
類型,您須要導入google/protobuf/any.proto
。
import "google/protobuf/any.proto";
message ErrorStatus {
string message = 1;
repeated google.protobuf.Any details = 2;
}
複製代碼
給定消息類型的默認類型URL是。 type.googleapis.com/*packagename*.*messagename*
不一樣的語言實現將支持運行時庫傭工類型安全的方式打包和解包的任何值-例如,在Java中,任何類型都會有特殊pack()
和unpack()
存取,而在C ++中有PackFrom()
和UnpackTo()
方法:
// Storing an arbitrary message type in Any.
NetworkErrorDetails details = ...;
ErrorStatus status;
status.add_details()->PackFrom(details);
// Reading an arbitrary message from Any.
ErrorStatus status = ...;
for (const Any& detail : status.details()) {
if (detail.Is<NetworkErrorDetails>()) {
NetworkErrorDetails network_error;
detail.UnpackTo(&network_error);
... processing network_error ...
}
}
複製代碼
目前,正在開發用於處理Any類型的運行時庫。
若是您有一個包含許多字段的消息,而且最多隻能同時設置一個字段,則可使用oneof功能強制執行此行爲並節省內存。
除了一個共享內存中的全部字段以外,其中一個字段相似於常規字段,而且最多能夠同時設置一個字段。設置oneof的任何成員會自動清除全部其餘成員。您可使用特殊case()
或WhichOneof()
方法檢查oneof中的哪一個值(若是有),具體取決於您選擇的語言。
要在您中定義oneof,請.proto
使用oneof
關鍵字後跟您的oneof名稱,在這種狀況下test_oneof
:
message SampleMessage {
oneof test_oneof {
string name = 4;
SubMessage sub_message = 9;
}
}
複製代碼
而後,將oneof字段添加到oneof定義中。您能夠添加任何類型的字段,但不能使用repeated
字段。
在生成的代碼中,oneof字段與常規字段具備相同的getter和setter。您還可使用特殊方法檢查oneof中的值(若是有)。您能夠在相關API參考中找到有關所選語言的oneof API的更多信息。
設置oneof字段將自動清除oneof的全部其餘成員。所以,若是您設置了多個字段,則只有您設置的
最後一個
字段仍然具備值。
SampleMessage message;
message.set_name("name");
CHECK(message.has_name());
message.mutable_sub_message(); // Will clear name field.
CHECK(!message.has_name());
複製代碼
若是解析器在線路上遇到同一個oneof的多個成員,則在解析的消息中僅使用看到的最後一個成員。
一個不可能repeated
。
Reflection API適用於其中一個字段。
若是您使用的是C ++,請確保您的代碼不會致使內存崩潰。如下示例代碼將崩潰,sub_message
已經過調用該set_name()
方法刪除了該代碼。
SampleMessage message;
SubMessage* sub_message = message.mutable_sub_message();
message.set_name("name"); // Will delete sub_message
sub_message->set_... // Crashes here
複製代碼
一樣在C ++中,若是你有Swap()
兩個消息與oneofs,每一個消息最終將與另外一個消息結果:在下面的例子中,msg1
將有一個sub_message
,msg2
並將有一name
。
SampleMessage msg1;
msg1.set_name("name");
SampleMessage msg2;
msg2.mutable_sub_message();
msg1.swap(&msg2);
CHECK(msg1.has_sub_message());
CHECK(msg2.has_name());
複製代碼
添加或刪除其中一個字段時要當心。若是檢查oneof返回的值None
/ NOT_SET
,這可能意味着oneof還沒有設置或已在不一樣版本的oneof的被設置爲一個字段。沒有辦法區分,由於沒有辦法知道線上的未知字段是不是其中一個成員。
若是要在數據定義中建立關聯映射,協議緩衝區提供了一種方便的快捷方式語法:
map < key_type ,value_type > map_field = N ;
複製代碼
...其中key_type
能夠是任何整數或字符串類型(所以,除了浮點類型以外的任何標量類型bytes
)。請注意,枚舉不是有效的key_type
。的value_type
能夠是任何類型的除另外一地圖。
所以,例如,若是要建立項目映射,其中每條Project
消息都與字符串鍵相關聯,則能夠像下面這樣定義它:
map < string ,Project > projects = 3 ;
複製代碼
repeated
。.proto
,地圖按鍵排序。數字鍵按數字排序。生成的地圖API目前可用於全部proto3支持的語言。您能夠在相關API參考中找到有關所選語言的地圖API的更多信息。
映射語法在線上等效於如下內容,所以不支持映射的協議緩衝區實現仍可處理您的數據:
message MapFieldEntry {
key_type key = 1;
value_type value = 2;
}
repeated MapFieldEntry map_field = N;
複製代碼
任何支持映射的協議緩衝區實現都必須生成和接受上述定義能夠接受的數據。
您能夠向.proto
文件添加package
可選說明符,以防止協議消息類型之間的名稱衝突。
package foo.bar;
message Open { ... }
複製代碼
而後,您能夠在定義消息類型的字段時使用包說明符:
message Foo {
...
foo.bar.Open open = 1;
...
}
複製代碼
包說明符影響生成的代碼的方式取決於您選擇的語言:
Open
將在命名空間中foo::bar
。option java_package
在.proto
文件中明確提供了該包。option go_package
在.proto
文件中明確提供。PB_
則前置)。例如,Open
將在命名空間中Foo::Bar
。option csharp_namespace
在.proto
文件中明確提供。例如,Open
將在命名空間中Foo.Bar
。協議緩衝區語言中的類型名稱解析與C ++相似:首先搜索最裏面的範圍,而後搜索下一個範圍,依此類推,每一個包被認爲是其父包的「內部」。一個領先的'。' (例如,.foo.bar.Baz
)意味着從最外層的範圍開始。
protobuf 編譯器經過解析導入的.proto
文件來解析全部類型名稱。每種語言的代碼生成器都知道如何使用該語言引用每種類型,即便它具備不一樣的範圍規則。
若是要將消息類型與RPC(遠程過程調用)系統一塊兒使用,則能夠在.proto
文件中定義RPC服務接口,protobuf 編譯器將使用您選擇的語言生成服務接口代碼和存根。所以,例如,若是要定義RPC服務請求方法爲:SearchRequest
和返回方法爲:SearchResponse
,能夠.proto
按以下方式在文件中定義它:
service SearchService {
rpc Search(SearchRequest)returns(SearchResponse);
}
複製代碼
與協議緩衝區一塊兒使用的最簡單的RPC系統是gRPC:一種由Google開發的,平臺中立的開源RPC系統。gRPC特別適用於protobuf,並容許在您的.proto
文件中使用特殊的protobuf 編譯器插件直接生成相關的RPC代碼。
若是您不想使用gRPC,也能夠將protobuf與您本身的RPC實現一塊兒使用。您能夠在Proto2語言指南中找到更多相關信息。
還有一些正在進行的第三方項目使用Protocol Buffers開發RPC實現。有關咱們瞭解的項目的連接列表,請參閱第三方加載項wiki頁面。
Proto3支持JSON中的規範編碼,使得在系統之間共享數據變得更加容易。在下表中逐個類型地描述編碼。
若是JSON編碼數據中缺乏值null
,或者其值爲,則在解析爲協議緩衝區時,它將被解釋爲適當的默認值。若是字段在協議緩衝區中具備默認值,則默認狀況下將在JSON編碼數據中省略該字段以節省空間。實現能夠提供用於在JSON編碼的輸出中發出具備默認值的字段的選項。
proto3 | JSON | JSON示例 | 筆記 |
---|---|---|---|
message | object | {"fooBar": v, "g": null,…} |
生成JSON對象。消息字段名稱映射到小寫駝峯併成爲JSON對象鍵。若是json_name 指定了field選項,則指定的值將用做鍵。解析器接受小寫駝峯名稱(或json_name 選項指定的名稱)和原始proto字段名稱。null 是全部字段類型的可接受值,並將其視爲相應字段類型的默認值。 |
eunm | String | "FOO_BAR" |
使用proto中指定的枚舉值的名稱。解析器接受枚舉名稱和整數值。 |
map<K,V> | object | {"k": v, …} |
全部鍵都轉換爲字符串。 |
repeated V. | array | [v, …] |
null 被接受爲空列表[]。 |
bool | true,false | true, false |
|
string | string | "Hello World!" |
|
bytes | base64 string | "YWJjMTIzIT8kKiYoKSctPUB+" |
JSON值將是使用帶填充的標準base64編碼編碼爲字符串的數據。接受帶有/不帶填充的標準或URL安全base64編碼。 |
int32,fixed32,uint32 | string | 1, -10, 0 |
JSON值將是十進制數。接受數字或字符串。 |
int64,fixed64,uint64 | string | "1", "-10" |
JSON值將是十進制字符串。接受數字或字符串。 |
float,double | number | 1.1, -10.0, 0, "NaN","Infinity" |
JSON值將是一個數字或一個特殊字符串值「NaN」,「Infinity」和「-Infinity」。接受數字或字符串。指數表示法也被接受。 |
any | object | {"@type": "url", "f": v, … } |
若是Any包含具備特殊JSON映射的值,則將按以下方式進行轉換:。不然,該值將轉換爲JSON對象,並將插入該字段以指示實際的數據類型。{"@type": xxx, "value": yyy}``"@type" |
Timestamp | string | "1972-01-01T10:00:20.021Z" |
使用RFC 3339,其中生成的輸出將始終被Z標準化並使用0,3,6或9個小數位。也接受「Z」之外的偏移。 |
Duration | string | "1.000340012s", "1s" |
生成的輸出始終包含0,3,6或9個小數位,具體取決於所需的精度,後跟後綴「s」。接受的是任何小數位(也沒有),只要它們符合納秒精度而且後綴「s」是必需的。 |
Struct | object |
{ … } |
任何JSON對象。見。struct.proto |
Wrapper types | various types | 2, "2", "foo", true,"true", null, 0, … |
包裝器在JSON中使用與包裝基元類型相同的表示形式,除了null 在數據轉換和傳輸期間容許和保留的表示形式。 |
FieldMask | string | "f.fooBar,h" |
見。field_mask.proto |
ListValue | array | [foo, bar, …] |
|
Value | value | 任何JSON值 | |
NullValue | null | JSON null |
proto3 JSON實現能夠提供如下選項:
.proto
文件中的各個聲明可使用許多選項進行註釋。選項不會更改聲明的總體含義,但可能會影響在特定上下文中處理它的方式。可用選項的完整列表在中定義google/protobuf/descriptor.proto
。
一些選項是文件級選項,這意味着它們應該在頂級範圍內編寫,而不是在任何消息,枚舉或服務定義中。一些選項是消息級選項,這意味着它們應該寫在消息定義中。一些選項是字段級選項,這意味着它們應該寫在字段定義中。選項也能夠寫在枚舉類型,枚舉值,服務類型和服務方法上; 可是,目前沒有任何有用的選擇。
如下是一些最經常使用的選項:
java_package
(文件選項):用於生成的Java類的包。若是.proto
文件中沒有給出顯式選項java_package
,則默認狀況下將使用proto包(使用文件中的「package」關鍵字指定 .proto )。可是,proto包一般不能生成好的Java包,由於proto包不會以反向域名開頭。若是不生成Java代碼,則此選項無效。
option java_package =「com.example.foo」;
複製代碼
java_multiple_files
(文件選項):致使在包級別定義頂級消息,枚舉和服務,而不是在.proto文件以後命名的外部類中。
option java_multiple_files = true;
複製代碼
java_outer_classname
(file option):要生成的最外層Java類(以及文件名)的類名。若是 .proto
文件中沒有指定 java_outer_classname
,則經過將.proto
文件名轉換爲駝峯格式(所以 foo_bar.proto
成爲FooBar.java
)來構造類名。若是不生成Java代碼,則此選項無效。option java_outer_classname =「Ponycopter」;
複製代碼
optimize_for
(文件選項):能夠設置爲SPEED
,CODE_SIZE
或LITE_RUNTIME
。這會如下列方式影響C ++和Java代碼生成器(可能還有第三方生成器):
SPEED
(默認值):protobuf 編譯器將生成用於對消息類型進行序列化,解析和執行其餘常見操做的代碼。此代碼通過高度優化。CODE_SIZE
:protobuf 編譯器將生成最少的類,並依賴於基於反射的共享代碼來實現序列化,解析和各類其餘操做。所以生成的代碼比使用SPEED
小得多,但操做會更慢。類仍將實現與SPEED
模式徹底相同的公共API 。此模式在包含很是大數量的.proto
文件的應用程序中最有用,而且不須要全部文件都很是快速。LITE_RUNTIME
:protobuf 編譯器將生成僅依賴於「lite」運行時庫(libprotobuf-lite
而不是libprotobuf
)的類。精簡版運行時比整個庫小得多(大約小一個數量級),但省略了描述符和反射等特定功能。這對於在移動電話等受限平臺上運行的應用程序尤爲有用。編譯器仍然會像在SPEED
模式中同樣生成全部方法的快速實現。生成的類將僅實現MessageLite
每種語言的接口,該接口僅提供完整Message
接口的方法的子集。option optimize_for = CODE_SIZE;
複製代碼
cc_enable_arenas
(文件選項):爲C ++生成的代碼啓用競技場分配。
objc_class_prefix
(文件選項):設置Objective-C類前綴,該前綴預先添加到此.proto的全部Objective-C生成的類和枚舉中。沒有默認值。您應該使用Apple建議的 3-5個大寫字符之間的前綴。請注意,Apple保留全部2個字母的前綴。
deprecated
(字段選項):若是設置爲true
,則表示該字段已棄用,新代碼不該使用該字段。在大多數語言中,這沒有實際效果。在Java中,這成爲一個@Deprecated
註釋。未來,其餘特定於語言的代碼生成器可能會在字段的訪問器上生成棄用註釋,這將致使在編譯嘗試使用該字段的代碼時發出警告。若是任何人都沒有使用該字段,而且您但願阻止新用戶使用該字段,請考慮使用保留語句替換字段聲明。
int32 old_field = 6 [deprecated = true];
複製代碼
Protocol Buffers還容許您定義和使用本身的選項。這是大多數人不須要的高級功能。若是您確實認爲須要建立本身的選項,請參閱Proto2語言指南以獲取詳細信息。請注意,建立自定義選項使用的擴展名僅容許用於proto3中的自定義選項。
根據實際工做須要,生成如下對應語言的自定義消息類型Java,Python,C ++,Go, Ruby, Objective-C,或C#的.proto
文件,你須要運行protobuf 編譯器protoc
上.proto
。若是還沒有安裝編譯器,請下載該軟件包並按照自述文件中的說明進行操做。對於Go,您還須要爲編譯器安裝一個特殊的代碼生成器插件:您能夠在GitHub上的golang / protobuf存儲庫中找到這個和安裝說明。
Protobuf 編譯器的調用以下:
protoc --proto_path = IMPORT_PATH --cpp_out = DST_DIR --java_out = DST_DIR --python_out = DST_DIR --go_out = DST_DIR --ruby_out = DST_DIR --objc_out = DST_DIR --csharp_out = DST_DIR path / to / file .proto
複製代碼
IMPORT_PATH
指定.proto
解析import
指令時在其中查找文件的目錄。若是省略,則使用當前目錄。能夠經過--proto_path
屢次傳遞選項來指定多個導入目錄; 他們將按順序搜索。 能夠用做簡短的形式。 -I=*IMPORT_PATH*``--proto_path
您能夠提供一個或多個輸出指令:
--cpp_out
生成C ++代碼DST_DIR
。有關更多信息,請參閱C ++生成的代碼參考。--java_out
生成Java代碼DST_DIR
。請參閱的Java生成的代碼參考更多。--python_out
生成Python代碼DST_DIR
。看到的Python生成的代碼的參考更多。--go_out
生成Go代碼DST_DIR
。有關更多信息,請參閱Go生成代碼參考。--ruby_out
生成Ruby代碼DST_DIR
。Ruby生成的代碼參考即將推出!--objc_out
生成Objective-C代碼DST_DIR
。有關更多信息,請參閱Objective-C生成的代碼參考。--csharp_out
生成C#代碼DST_DIR
。有關更多信息,請參閱C#生成的代碼參考。--php_out
生成PHP代碼DST_DIR
。看到PHP生成的代碼的參考更多。爲了方便起見,若是DST_DIR結束於.zip
或.jar
,編譯器會將輸出寫入具備給定名稱的單個ZIP格式存檔文件。.jar
輸出還將根據Java JAR規範的要求提供清單文件。請注意,若是輸出存檔已存在,則會被覆蓋; 編譯器不夠智能,沒法將文件添加到現有存檔中。
您必須提供一個或多個.proto
文件做爲輸入。.proto
能夠一次指定多個文件。雖然文件是相對於當前目錄命名的,但每一個文件必須位於其中一個文件中,IMPORT_PATH
以便編譯器能夠肯定其規範名稱。