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