proto 指定字段json名_比json快5倍的protobuf了解一下
自己在學習 ProtoBuf 的過程中翻譯了官方的主要文檔,一來當然是在學習 ProtoBuf,二來是培養(yǎng)閱讀英文文檔的能力,三來是因為 Google 的文檔?不存在的!看完這些文檔對 ProtoBuf 應該就有相當程度的了解了。
但是官方文檔更多的是作為查閱和權威參考,并不意味著看完官方文檔就能立馬理解其原理,本文以及接下來的幾篇文章會對 ProtoBuf 的編碼、序列化、反序列化、反射等原理做一些詳細介紹,同時也會盡量將這些原理表達的更為通俗易懂。
何為 ProtoBuf
我們先來看看官方文檔給出的定義和描述:
protocol buffers 是一種語言無關、平臺無關、可擴展的序列化結構數(shù)據的方法,它可用于(數(shù)據)通信協(xié)議、數(shù)據存儲等。Protocol Buffers 是一種靈活,高效,自動化機制的結構數(shù)據序列化方法-可類比 XML,但是比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更為簡單。你可以定義數(shù)據的結構,然后使用特殊生成的源代碼輕松的在各種數(shù)據流中使用各種語言進行編寫和讀取結構數(shù)據。你甚至可以更新數(shù)據結構,而不破壞由舊數(shù)據結構編譯的已部署程序。簡單來講, ProtoBuf 是結構數(shù)據序列化方法,可簡單類比于 XML,其具有以下特點:
- 語言無關、平臺無關。即 ProtoBuf 支持 Java、C++、Python 等多種語言,支持多個平臺
- 高效。即比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更為簡單
- 擴展性、兼容性好。你可以更新數(shù)據結構,而不影響和破壞原有的舊程序
使用 ProtoBuf
對 ProtoBuf 的基本概念有了一定了解之后,我們來看看具體該如何使用 ProtoBuf。
第一步,創(chuàng)建 .proto 文件,定義數(shù)據結構,如下例1所示:
// 例1: 在 xxx.proto 文件中定義 Example1 messagemessage Example1 { optional string stringVal = 1; optional bytes bytesVal = 2; message EmbeddedMessage { int32 int32Val = 1; string stringVal = 2; } optional EmbeddedMessage embeddedExample1 = 3; repeated int32 repeatedInt32Val = 4; repeated string repeatedStringVal = 5;}我們在上例中定義了一個名為 Example1 的 消息,語法很簡單,message 關鍵字后跟上消息名稱:
message xxx {}之后我們在其中定義了 message 具有的字段,形式為:
message xxx { // 字段規(guī)則:required -> 字段只能也必須出現(xiàn) 1 次 // 字段規(guī)則:optional -> 字段可出現(xiàn) 0 次或1次 // 字段規(guī)則:repeated -> 字段可出現(xiàn)任意多次(包括 0) // 類型:int32、int64、sint32、sint64、string、32-bit .... // 字段編號:0 ~ 536870911(除去 19000 到 19999 之間的數(shù)字) 字段規(guī)則 類型 名稱 = 字段編號;}在上例中,我們定義了:
- 類型 string,名為 stringVal 的 optional 可選字段,字段編號為 1,此字段可出現(xiàn) 0 或 1 次
- 類型 bytes,名為 bytesVal 的 optional 可選字段,字段編號為 2,此字段可出現(xiàn) 0 或 1 次
- 類型 EmbeddedMessage(自定義的內嵌 message 類型),名為 embeddedExample1 的 optional 可選字段,字段編號為 3,此字段可出現(xiàn) 0 或 1 次
- 類型 int32,名為 repeatedInt32Val 的 repeated 可重復字段,字段編號為 4,此字段可出現(xiàn) 任意多次(包括 0)
- 類型 string,名為 repeatedStringVal 的 repeated 可重復字段,字段編號為 5,此字段可出現(xiàn) 任意多次(包括 0)
第二步,protoc 編譯 .proto 文件生成讀寫接口
我們在 .proto 文件中定義了數(shù)據結構,這些數(shù)據結構是面向開發(fā)者和業(yè)務程序的,并不面向存儲和傳輸。
當需要把這些數(shù)據進行存儲或傳輸時,就需要將這些結構數(shù)據進行序列化、反序列化以及讀寫。那么如何實現(xiàn)呢?不用擔心, ProtoBuf 將會為我們提供相應的接口代碼。如何提供?答案就是通過 protoc 這個編譯器。
可通過如下命令生成相應的接口代碼:
// $SRC_DIR: .proto 所在的源目錄// --cpp_out: 生成 c++ 代碼// $DST_DIR: 生成代碼的目標目錄// xxx.proto: 要針對哪個 proto 文件生成接口代碼protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/xxx.proto最終生成的代碼將提供類似如下的接口:
第三步,調用接口實現(xiàn)序列化、反序列化以及讀寫
針對第一步中例1定義的 message,我們可以調用第二步中生成的接口,實現(xiàn)測試代碼如下:
Created by yue on 18-7-21.//#include #include #include #include "single_length_delimited_all.pb.h"int main() { Example1 example1; example1.set_stringval("hello,world"); example1.set_bytesval("are you ok?"); Example1_EmbeddedMessage *embeddedExample2 = new Example1_EmbeddedMessage(); embeddedExample2->set_int32val(1); embeddedExample2->set_stringval("embeddedInfo"); example1.set_allocated_embeddedexample1(embeddedExample2); example1.add_repeatedint32val(2); example1.add_repeatedint32val(3); example1.add_repeatedstringval("repeated1"); example1.add_repeatedstringval("repeated2"); std::string filename = "single_length_delimited_all_example1_val_result"; std::fstream output(filename, std::ios::out | std::ios::trunc | std::ios::binary); if (!example1.SerializeToOstream(&output)) { std::cerr << "Failed to write example1." << std::endl; exit(-1); } return 0;}關于 ProtoBuf 的一些思考
官方文檔以及網上很多文章提到 ProtoBuf 可類比 XML 或 JSON。
那么 ProtoBuf 是否就等同于 XML 和 JSON 呢,它們是否具有完全相同的應用場景呢?
個人認為如果要將 ProtoBuf、XML、JSON 三者放到一起去比較,應該區(qū)分兩個維度。一個是數(shù)據結構化,一個是數(shù)據序列化。這里的數(shù)據結構化主要面向開發(fā)或業(yè)務層面,數(shù)據序列化面向通信或存儲層面,當然數(shù)據序列化也需要“結構”和“格式”,所以這兩者之間的區(qū)別主要在于面向領域和場景不同,一般要求和側重點也會有所不同。數(shù)據結構化側重人類可讀性甚至有時會強調語義表達能力,而數(shù)據序列化側重效率和壓縮。
從這兩個維度,我們可以做出下面的一些思考。
XML 作為一種擴展標記語言,JSON 作為源于 JS 的數(shù)據格式,都具有數(shù)據結構化的能力。例如 XML 可以衍生出 HTML (雖然 HTML 早于 XML,但從概念上講,HTML 只是預定義標簽的 XML),HTML 的作用是標記和表達萬維網中資源的結構,以便瀏覽器更好的展示萬維網資源,同時也要盡可能保證其人類可讀以便開發(fā)人員進行編輯,這就是面向業(yè)務或開發(fā)層面的數(shù)據結構化。
再如 XML 還可衍生出 RDF/RDFS,進一步表達語義網中資源的關系和語義,同樣它強調數(shù)據結構化的能力和人類可讀。
關于 RDF/RDFS 和語義網的概念可查詢相關資料了解,或參閱 2-Answer 系列-本體構建模塊(一) 和 3-Answer 系列-本體構建模塊(二) ,文中有一些簡單介紹。JSON 也是同理,在很多場合更多的是體現(xiàn)了數(shù)據結構化的能力,例如作為交互接口的數(shù)據結構的表達。在 MongoDB 中采用 JSON 作為查詢語句,也是在發(fā)揮其數(shù)據結構化的能力。
當然,JSON、XML 同樣也可以直接被用來數(shù)據序列化,實際上很多時候它們也是這么被使用的,例如直接采用 JSON、XML 進行網絡通信傳輸,此時 JSON、XML 就成了一種序列化格式,它發(fā)揮了數(shù)據序列化的能力。但是經常這么被使用,不代表這么做就是合理。實際將 JSON、XML 直接作用數(shù)據序列化通常并不是最優(yōu)選擇,因為它們在速度、效率、空間上并不是最優(yōu)。換句話說它們更適合數(shù)據結構化而非數(shù)據序列化。
扯完 XML 和 JSON,我們來看看 ProtoBuf,同樣的 ProtoBuf 也具有數(shù)據結構化的能力,其實也就是上面介紹的 message 定義。我們能夠在 .proto 文件中,通過 message、import、內嵌 message 等語法來實現(xiàn)數(shù)據結構化,但是很容易能夠看出,ProtoBuf 在數(shù)據結構化方面和 XML、JSON 相差較大,人類可讀性較差,不適合上面提到的 XML、JSON 的一些應用場景。
但是如果從數(shù)據序列化的角度你會發(fā)現(xiàn) ProtoBuf 有著明顯的優(yōu)勢,效率、速度、空間幾乎全面占優(yōu),看完后面的 ProtoBuf 編碼的文章,你更會了解 ProtoBuf 是如何極盡所能的壓榨每一寸空間和性能,而其中的編碼原理正是 ProtoBuf 的關鍵所在,message 的表達能力并不是 ProtoBuf 最關鍵的重點。所以可以看出 ProtoBuf 重點側重于數(shù)據序列化 而非 數(shù)據結構化。
最終對這些個人思考做一些小小的總結:
總結
以上是生活随笔為你收集整理的proto 指定字段json名_比json快5倍的protobuf了解一下的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 接口responsecode返回500_
- 下一篇: qt 进度条_Qt开源作品12-硬盘容量