日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

快来看看Google出品的Protocol Buffer,别仅仅会用Json和XML了

發(fā)布時間:2025/4/16 asp.net 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 快来看看Google出品的Protocol Buffer,别仅仅会用Json和XML了 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前言

  • 習慣用 Json、XML 數(shù)據(jù)存儲格式的你們,相信大多都沒聽過Protocol Buffer
  • Protocol Buffer 事實上 是 Google出品的一種輕量 & 高效的結(jié)構化數(shù)據(jù)存儲格式,性能比 Json、XML 真的強!太!

    多!

    由于 Google出品,我相信Protocol Buffer已經(jīng)具備足夠的吸引力
  • 今天,我將獻上一份 Protocol Buffer的介紹 & 使用攻略,希望你們會喜歡。

文件夾


1. 定義

一種 結(jié)構化數(shù)據(jù) 的數(shù)據(jù)存儲格式(相似于 `XML、Json` )
  • Google 出品 (開源)
  • Protocol Buffer 眼下有兩個版本號:proto2 和 proto3
  • 由于proto3 還是beta 版,所以本次解說是 proto2

  • 2. 作用

    通過將 結(jié)構化的數(shù)據(jù) 進行 串行化(**序列化**),從而實現(xiàn) **數(shù)據(jù)存儲 / RPC 數(shù)據(jù)交換**的功能
  • 序列化: 將 數(shù)據(jù)結(jié)構或?qū)ο?轉(zhuǎn)換成 二進制串 的過程
  • 反序列化:將在序列化過程中所生成的二進制串 轉(zhuǎn)換成 數(shù)據(jù)結(jié)構或者對象 的過程

  • 3. 特點

    • 對照于 常見的 XML、Json 數(shù)據(jù)存儲格式。Protocol Buffer有例如以下特點:


    4. 應用場景

    數(shù)據(jù)傳輸量大 & 網(wǎng)絡環(huán)境不穩(wěn)定 的數(shù)據(jù)存儲、RPC 數(shù)據(jù)交換 的需求場景

    如 即時IM (QQ、微信)的需求場景


    總結(jié)

    數(shù)據(jù)傳輸量較大的需求場景下,Protocol Buffer比XML、Json 更小、更快、使用 & 維護更簡單!


    5. 使用流程

    使用 Protocol Buffer 的流程例如以下:

    5.1 環(huán)境配置

    • 要使用Protocol Buffer 。須要先在電腦上安裝Protocol Buffer

    • 整個 安裝過程 僅僅須要依照以下步驟進行就可以:

      整個安裝過程請 自備梯子 以保證 網(wǎng)絡暢通

    步驟1:下載 Protocol Buffer 安裝包


    • 下載方式1:官網(wǎng)下載(須要FQ)
    • 下載方式2:貼心的我 已經(jīng)給你們準備好了,請移步百度網(wǎng)盤。password:paju

    此處選擇 較穩(wěn)定的版本號 protobuf-2.6.1.tar.gz 進行演示
    下載成功后,對文件進行解壓,例如以下圖:

    步驟2:安裝 HOMEBREW(已安裝的能夠跳過)

    // 打開 終端 輸入以下指令 /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

    步驟3:安裝 Protocol Buffer

    打開 您的終端 依次輸入 下列指令 就可以:

    brew install autoconf automake libtool curl // Step1:安裝 Protocol Buffer 依賴 // 注:Protocol Buffer 依賴于 autoconf、automake、libtool、curlcd Desktop/protobuf-2.6.1 // Step2:進入 Protocol Buffer安裝包 解壓后的文件夾(我的解壓文件放在桌面)./autogen.sh // Step3:執(zhí)行 autogen.sh 腳本./configure // Step4:執(zhí)行 configure.sh 腳本make // Step5:編譯未編譯的依賴包make check // Step6:檢查依賴包是否完整make install // Step7:開始安裝Protocol Buffer

    步驟4:檢查 Protocol Buffer 是否成功安裝

    // 在 終端 下輸入 protoc - - version

    出現(xiàn) libprotoc 2.6.1 提示即表示 成功安裝。例如以下圖

    特別注意:

    • protoc = Protocol Buffer的編譯器
    • 作用:將 .proto文件 編譯成相應平臺的 頭文件和源碼文件
    • 在以下會詳細介紹

    至此, Protocol Buffer已經(jīng)安裝完畢。以下將解說怎樣詳細使用Protocol Buffer


    5.2 構建 Protocol Buffer 消息對象模型

    5.2.1 構建步驟

    以下將通過一個實例(Android(Java) 平臺為例)詳細介紹每一個步驟。

    5.2.2 詳細介紹

    • 實例說明:構建一個Person類的數(shù)據(jù)結(jié)構。包括成員變量name、id、email等等
    // Java類public class Person {private String name;private Int id;private String email; ... }
    • 平臺使用:以 Android(Java) 平臺為例來進行演示

    步驟1:通過 Protocol Buffer 語法 描寫敘述 須要存儲的數(shù)據(jù)結(jié)構

    • 新建一個文件,命名規(guī)則為:文件名稱 = 類名,后綴為 .proto

      此處叫Demo.proto


    • 依據(jù)上述數(shù)據(jù)結(jié)構的需求。在Demo.proto里 通過 Protocol Buffer 語法寫入相應 .proto對象模型的代碼,例如以下:
    package protocobuff_Demo; // 關注1:包名option java_package = "com.carson.proto"; option java_outer_classname = "Demo"; // 關注2:option選項// 關注3:消息模型 // 以下詳細說明 // 生成 Person 消息對象(包括多個字段。以下詳細說明) 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 phone = 4; }message AddressBook {repeated Person person = 1; }
    • 以下將結(jié)合 上述樣例 對 Protocol Buffer 語法 進行詳細介紹

    關注1:包名

    package protocobuff_Demo; // 關注1:包名
    • 作用:防止不同 .proto 項目間命名 發(fā)生沖突
    • Protocol buffer包的解析過程例如以下:
    • Protocol buffer 的類型名稱解析與 C++ 一致:從 最內(nèi)部 開始查找,依次 向外 進行
      每一個包會被看作是其父類包的內(nèi)部類
    • Protocol buffer 編譯器會解析 .proto文件里定義的全部類型名
    • 生成器會依據(jù) 不同語言 生成 相應語言 的代碼文件
      a. 即對 不同語言 使用了 不同的規(guī)則 進行處理
      b. Protoco Buffer提供 C++、Java、Python 三種語言的 API

    關注2:Option選項

    option java_package = "com.carson.proto"; option java_outer_classname = "Demo"; // 關注2:option選項
    • 作用:影響 特定環(huán)境下 的處理方式

      但不改變整個文件聲明的含義

    • 經(jīng)常使用Option選項例如以下:

    option java_package = "com.carson.proto"; // 定義:Java包名 // 作用:指定生成的類應該放在什么Java包名下 // 注:如不顯式指定,默認包名為:依照顧用名稱倒序方式進行排序option java_outer_classname = "Demo"; // 定義:類名 // 作用:生成相應.java 文件的類名(不能跟以下message的類名同樣) // 注:如不顯式指定,則默覺得把.proto文件名稱轉(zhuǎn)換為首字母大寫來生成 // 如.proto文件名稱="my_proto.proto",默認情況下,將使用 "MyProto" 做為類名option optimize_for = ***; // 作用:影響 C++ & java 代碼的生成 // ***參數(shù)例如以下: // 1. SPEED (默認)::protocol buffer編譯器將通過在消息類型上執(zhí)行序列化、語法分析及其它通用的操作。(最優(yōu)方式) // 2. CODE_SIZE::編譯器將會產(chǎn)生最少量的類,通過共享或基于反射的代碼來實現(xiàn)序列化、語法分析及各種其它操作。// 特點:採用該方式產(chǎn)生的代碼將比SPEED要少非常多。 可是效率較低;// 使用場景:經(jīng)常使用在 包括大量.proto文件 但 不追求效率 的應用中。

    //3. LITE_RUNTIME::編譯器依賴于執(zhí)行時 核心類庫 來生成代碼(即採用libprotobuf-lite 替代libprotobuf)。 // 特點:這樣的核心類庫要比全類庫小得多(忽略了 一些描寫敘述符及反射 );編譯器採用該模式產(chǎn)生的方法實現(xiàn)與SPEED模式不相上下,產(chǎn)生的類通過實現(xiàn) MessageLite接口,但它僅僅是Messager接口的一個子集。

    // 應用場景:移動手機平臺應用 option cc_generic_services = false; option java_generic_services = false; option py_generic_services = false; // 作用:定義在C++、java、python中,protocol buffer編譯器是否應該 基于服務定義 產(chǎn)生 抽象服務代碼(2.3.0版本號前該值默認 = true) // 自2.3.0版本號以來,官方覺得通過提供 代碼生成器插件 來對 RPC實現(xiàn) 更可取,而不是依賴于“抽象”服務 optional repeated int32 samples = 4 [packed=true]; // 假設該選項在一個整型基本類型上被設置為真,則採用更緊湊的編碼方式(不會對數(shù)值造成損失) // 在2.3.0版本號前。解析器將會忽略 非期望的包裝值。因此,它不可能在 不破壞現(xiàn)有框架的兼容性上 而 改變壓縮格式。 // 在2.3.0之后,這樣的改變將是安全的。解析器能夠接受上述兩種格式。 optional int32 old_field = 6 [deprecated=true]; // 作用:推斷該字段是否已經(jīng)被棄用 // 作用同 在java中的注解@Deprecated
    • 在 ProtocolBuffers 中同意 自己定義選項 并 使用
    • 該功能屬于高級特性。使用頻率非常低,此處只是多描寫敘述。有興趣可查看官方文檔

    關注3:消息模型

    • 作用:真正用于描寫敘述 數(shù)據(jù)結(jié)構
    // 消息對象用message修飾 message Person {required string name = 1;required int32 id = 2;optional string email = 3;enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2;}message PhoneNumber {optional PhoneType type = 2 [default = HOME];}repeated PhoneNumber phone = 4; }message AddressBook {repeated Person person = 1; }
    • 組成:在 ProtocolBuffers 中:
    • 一個 .proto 消息模型 = 一個 .proto文件 = 消息對象 + 字段
    • 一個消息對象(Message) = 一個 結(jié)構化數(shù)據(jù)
    • 消息對象(Message)里的 字段 = 結(jié)構化數(shù)據(jù) 里的成員變量

    以下會詳細介紹 .proto 消息模型里的 消息對象 & 字段

    1. 消息對象

    在 ProtocolBuffers 中:

    • 一個消息對象(Message) = 一個 結(jié)構化數(shù)據(jù)
    • 消息對象用 修飾符 message 修飾
    • 消息對象 含有 字段:消息對象(Message)里的 字段 = 結(jié)構化數(shù)據(jù) 里的成員變量

    特別注意:

    a. 加入:在一個 .proto文件 中可定義多個 消息對象

    • 應用場景:盡可能將與 某一消息類型 相應的響應消息格式 定義到同樣的 .proto文件 中
    • 實例:
    message SearchRequest {required string query = 1;optional int32 page_number = 2;optional int32 result_per_page = 3;}// 與SearchRequest消息類型 相應的 響應消息類型SearchResponse message SearchResponse {… }

    b. 一個消息對象 里 能夠定義 另外一個消息對象(即嵌套)

    message Person {required string name = 1;required int32 id = 2;optional string email = 3;// 該消息類型 定義在 Person消息類型的內(nèi)部 // 即Person消息類型 是 PhoneNumber消息類型的父消息類型message PhoneNumber {required string number = 1;} }<-- 多重嵌套 --> message Outer { // Level 0message MiddleAA { // Level 1message Inner { // Level 2required int64 ival = 1;optional bool booly = 2;}} }

    2. 字段

    • 消息對象的字段 組成主要是:字段 = 字段修飾符 + 字段類型 +字段名 +標識號

    • 以下將對每一項詳細介紹

    a. 字段修飾符

    • 作用:設置該字段解析時的規(guī)則
    • 詳細類型例如以下:

    b. 字段類型

    字段類型主要有 三 類:

    • 基本數(shù)據(jù) 類型
    • 枚舉 類型
    • 消息對象 類型
    message Person {// 基本數(shù)據(jù)類型 字段required string name = 1;required int32 id = 2;optional string email = 3;enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2;}message PhoneNumber {optional PhoneType type = 2 [default = HOME];// 枚舉類型 字段}repeated PhoneNumber phone = 4;// 消息類型 字段 }

    1. 基本數(shù)據(jù)類型

    .proto基本數(shù)據(jù)類型 相應于 各平臺的基本數(shù)據(jù)類型例如以下:

    2. 枚舉類型

    • 作用:為字段指定一個 可能取值的字段集合
      該字段僅僅能從 該指定的字段集合里 取值
    • 說明:如以下樣例,電話號碼 可能是手機號、家庭電話號或工作電話號的當中一個。那么就將PhoneType定義為枚舉類型,并將加入電話的集合( MOBILE、 HOME、WORK)
    // 枚舉類型須要先定義才干進行使用// 枚舉類型 定義enum PhoneType {MOBILE = 0;HOME = 1;WORK = 2; // 電話類型字段 僅僅能從 這個集合里 取值}// 特別注意: // 1. 枚舉類型的定義可在一個消息對象的內(nèi)部或外部 // 2. 都能夠在 同一.proto文件 中的不論什么消息對象里使用 // 3. 當枚舉類型是在一消息內(nèi)部定義,希望在 還有一個消息中 使用時。須要採用MessageType.EnumType的語法格式message PhoneNumber {required string number = 1;optional PhoneType type = 2 [default = HOME];// 使用枚舉類型的字段(設置了默認值)}// 特別注意: // 1. 枚舉常量必須在32位整型值的范圍內(nèi) // 2. 不推薦在enum中使用負數(shù):由于enum值是使用可變編碼方式的。對負數(shù)不夠高

    額外說明

    當對一個 使用了枚舉類型的.proto文件 使用 Protocol Buffer編譯器編譯時,生成的代碼文件里:


    • 對 Java 或 C++來說。將有一個相應的 enum 文件
    • 對 Python 來說。有一個特殊的EnumDescriptor 類

    被用來在執(zhí)行時生成的類中創(chuàng)建一系列的整型值符號常量(symbolic constants)

    3. 消息對象 類型

    一個消息對象 能夠?qū)?其它消息對象類型 用作字段類型。情況例如以下:

    3.1 使用同一個 .proto 文件里的消息類型

    a. 使用 內(nèi)部消息類型

    • 目的:先在 消息類型 中定義 其它消息類型 。然后再使用

      即嵌套,須要 用作字段類型的 消息類型 定義在 該消息類型里

    • 實例:

    message Person {required string name = 1;required int32 id = 2;optional string email = 3;// 該消息類型 定義在 Person消息類型的內(nèi)部 // 即Person消息類型 是 PhoneNumber消息類型的父消息類型message PhoneNumber {required string number = 1;}repeated PhoneNumber phone = 4;// 直接使用內(nèi)部消息類型 }

    b. 使用 外部消息類型

    即外部重用。須要 用作字段類型的消息類型 定義在 該消息類型外部

    message Person {required string name = 1;required int32 id = 2;optional string email = 3; }message AddressBook {repeated Person person = 1;// 直接使用了 Person消息類型作為消息字段 }

    c. 使用 外部消息的內(nèi)部消息類型

    message Person {required string name = 1;required int32 id = 2;optional string email = 3;// PhoneNumber消息類型 是 Person消息類型的內(nèi)部消息類型message PhoneNumber {required string number = 1;optional PhoneType type = 2 [default = HOME];} }// 若父消息類型外部的消息類型須要重用該內(nèi)部消息類型 // 須要以 Parent.Type 的形式去使用 // Parent = 須要使用消息類型的父消息類型。Type = 須要使用的消息類型// PhoneNumber父消息類型Person 的外部 OtherMessage消息類型 須要使用 PhoneNumber消息類型 message OtherMessage {optional Person.PhoneNumber phonenumber = 1; // 以 Parent.Type = Person.PhoneNumber 的形式去使用}

    3.2 使用不同 .proto 文件里的消息類型

    • 目的:須要在 A.proto文件 使用 B.proto文件里的消息類型
    • 解決方式:在 A.proto文件 通過導入( import) B.proto文件里來使用 B.proto文件 里的消息類型
    import "myproject/other_protos.proto" // 在A.proto 文件里加入 B.proto文件路徑的導入聲明 // ProtocolBuffer編譯器 會在 該文件夾中 查找須要被導入的 .proto文件 // 假設不提供參數(shù)。編譯器就在 其調(diào)用的文件夾下 查找

    當然,在使用 不同 .proto 文件里的消息類型 時 也會存在想 使用同一個 .proto 文件消息類型的情況,但使用都是一樣,此處不作過多描寫敘述。

    3.3 將 消息對象類型 用在 RPC(遠程方法調(diào)用)系統(tǒng)

    • 解決方式:在 .proto 文件里定義一個 RPC 服務接口,Protocol Buffer編譯器會依據(jù)所選擇的不同語言平臺 生成服務接口代碼
    • 由于使用得不多,此處不作過多描寫敘述。詳細請看該文檔

    c. 字段名

    該字段的名稱,此處不作過多描寫敘述。


    d. 標識號

    • 作用:通過二進制格式唯一標識每一個字段

    • 一旦開始使用就不能夠再改變
    • 標識號使用范圍:[1,2的29次方 - 1]
    • 不可使用 [19000-19999] 標識號, 由于 Protobuf 協(xié)議實現(xiàn)中對這些標識號進行了預留。假若使用,則會報錯
    • 編碼占有內(nèi)存規(guī)則:
      每一個字段在進行編碼時都會占用內(nèi)存,而 占用內(nèi)存大小 取決于 標識號:

    • 范圍 [1,15] 標識號的字段 在編碼時占用1個字節(jié)。
    • 范圍 [16,2047] 標識號的字段 在編碼時占用2個字節(jié)
    • 使用建議

    • 為頻繁出現(xiàn)的 消息字段 保留 [1,15] 的標識號
    • 為將來有可能加入的、頻繁出現(xiàn)的 消息字段預留 [1,15] 標識號

    關于 字段 的高級使用方法

    1. 更新消息對象 的字段

    • 目的:為了滿足新需求,須要更新 消息類型 而不破壞已有消息類型代碼

      即新、老版本號須要兼容

    • 更新字段時,須要符合下列規(guī)則:

    2. 擴展消息對象 的字段

    • 作用:使得其它人能夠在自己的 .proto 文件里為 該消息對象 聲明新的字段而不必去編輯原始文件
    • 注:擴展 能夠是消息類型也能夠是字段類型
    • 以下以 擴展 消息類型 為例

    A.proto message Request { …extensions 100 to 199;// 將一個范圍內(nèi)的標識號 聲明為 可被第三方擴展所用// 在消息Request中。范圍 [100,199] 的標識號被保留為擴展用// 假設標識號須要非常大的數(shù)量時。能夠?qū)⒖蓴U展標符號的范圍擴大至max// 當中max是2的29次方 - 1(536,870,911)。

    message Request { extensions 1000 to max; // 注:請避開[19000-19999] 的標識號。由于已被Protocol Buffers實現(xiàn)中預留 }

    如今,其它人 就能夠在自己的 .proto文件里 加入新字段到Request里。例如以下:

    B.proto

    extend Request {optional int32 bar = 126;// 加入字段的 標識號必須要在指定的范圍內(nèi)// 消息Request 如今有一個名為 bar 的 optional int32 字段// 當Request消息被編碼時,數(shù)據(jù)的傳輸格式與在Request里定義新字段的效果是全然一樣的// 注:在同一個消息類型中一定要確保不會擴展新增同樣的標識號。否則會導致數(shù)據(jù)不一致;能夠通過為新項目定義一個可擴展標識號規(guī)則來防止該情況的發(fā)生 }
    • 要訪問 擴展字段 的方法與 訪問普通的字段 不同:使用專門的擴展訪問函數(shù)
    • 實例:
    // 怎樣在C++中設置 bar 值 Request request; request.SetExtension(bar, 15); // 相似的模板函數(shù) HasExtension()。ClearExtension(),GetExtension(),MutableExtension(),以及 AddExtension() // 與相應的普通字段的訪問函數(shù)相符

    嵌套的擴展

    能夠在還有一個 消息對象里 聲明擴展,如:

    message Carson {extend Request {optional int32 bar = 126;}… }// 訪問此擴展的C++代碼: Request request; request.SetExtension(Baz::bar, 15);
    • 對于嵌套的使用,一般的做法是:在擴展的字段類型的范圍內(nèi)定義該擴展
    • 實例:一個 Request 消息對象須要擴展(擴展的字段類型是Car 消息類型)。那么,該擴展就定義在 Car消息類型 里:
    message Car {extend Request {optional Car request_ext = 127; // 注:二者并沒有子類、父類的關系} }
    • 至此,Protoco Buffer的語法已經(jīng)解說完畢
    • 關于怎樣依據(jù)需求 通過Protoco Buffer語法 去構建 數(shù)據(jù)結(jié)構 相信大家已經(jīng)非常熟悉了。
    • 在將 .proto文件保存后,進入下一個步驟

    步驟2:通過 Protocol Buffer 編譯器 編譯 .proto 文件

    • 作用:將 .proto 文件 轉(zhuǎn)換成 相應平臺的代碼文件

      Protoco Buffer提供 C++、Java、Python 三種開發(fā)語言的 API

    • 詳細生成文件與平臺有關:

    • 編譯指令說明
    // 在 終端 輸入下列命令進行編譯 protoc -I=$SRC_DIR --xxx_out=$DST_DIR $SRC_DIR/addressbook.proto// 參數(shù)說明 // 1. $SRC_DIR:指定須要編譯的.proto文件文件夾 (如沒有提供則使用當前文件夾) // 2. --xxx_out:xxx依據(jù)須要生成代碼的類型進行設置 // 對于 Java ,xxx = java ,即 -- java_out // 對于 C++ ,xxx = cpp ,即 --cpp_out // 對于 Python。xxx = python。即 --python_out// 3. $DST_DIR :編譯后代碼生成的文件夾 (通常設置與$SRC_DIR同樣) // 4. 最后的路徑參數(shù):須要編譯的.proto 文件的詳細路徑// 編譯通過后。Protoco Buffer會依據(jù)不同平臺生成相應的代碼文件
    • 詳細實例
    // 編譯說明 // 1. 生成Java代碼 // 2. 須要編譯的.proto文件在桌面,希望編譯后生成的代碼也放在桌面 protoc -I=/Users/Carson_Ho/Desktop --java_out=/Users/Carson_Ho/Desktop /Users/Carson_Ho/Desktop/Demo.proto// 編譯通過后,Protoco Buffer會依照標準Java風格。生成Java類及文件夾結(jié)構

    在指定的文件夾能看到一個Demo的包文件(含 java類文件)

    編譯功能的拓展

    a. 使用Android Studio插件進行編譯

    • 需求場景:每次手動執(zhí)行 Protocol Buffer 編譯器將 .proto 文件轉(zhuǎn)換為 Java 文件 操作不方便
    • 解決方式:使用 Android Studio的 gradle 插件 protobuf-gradle-plugin,以便于在項目編譯時 自己主動執(zhí)行 Protocol Buffers 編譯器

    關于protobuf-gradle-plugin插件有興趣的讀者可自行了解。但個人還是建議使用 命令行,畢竟太過折騰插件不是必需

    b. 動態(tài)編譯

    • 需求場景:某些情況下。人們無法預先知道 .proto 文件,他們須要動態(tài)處理一些未知的 .proto 文件

      如一個通用的消息轉(zhuǎn)發(fā)中間件。它無法預先知道須要處理什么類型的數(shù)據(jù)結(jié)構消息

    • 解決方式:動態(tài)編譯.proto文件

    由于使用得不多,此處不作過多描寫敘述。詳細請看官方文檔

    c. 編寫新的 .proto 編譯器

    • 需求場景: Protocol Buffer 僅支持 C++、java 和 Python 三種開發(fā)語言。一旦超出該三種開發(fā)語言,Protocol Buffer將無法使用
    • 解決方式:使用 Protocol Buffer 的 Compiler 包 開發(fā)出支持其它語言的新的.proto編譯器

    由于使用得不多,此處不作過多描寫敘述,詳細請看官方文檔


    5.3 應用到詳細平臺(Android平臺)

    • 最終到了應用到詳細平臺項目中的步驟了。

      此處以 Android平臺 為例

    • 詳細過程例如以下:

    步驟1:將生成的 代碼文件 放入到項目中

    • 對于Android(Java)平臺。即將編譯.proto文件生成的Java包文件 整個拷貝到 Android 項目中
    • 放置路徑: app/src/main/java的 文件夾里

    步驟2:在 Gradle 加入 Protocol Buffer 版本號依賴

    compile 'com.google.protobuf:protobuf-java:2.6.1' // 注:protobuf-java的版本號 一定要和 安裝protocobuffer的版本號 一致

    步驟3:詳細在Android項目中使用

    3.1 消息對象類介紹

    通過.proto文件 轉(zhuǎn)換的 Java源碼 = Protocol Buffer 類 + 消息對象類(含Builder內(nèi)部類)

    消息對象類 是 Protocol Buffer 類的內(nèi)部類

    由于最經(jīng)常使用的都是 消息對象類 和其內(nèi)部類Builder類 的方法&成員變量,所以此處主要解說這兩者。

    3.1.1 消息對象類(Message類)
    • 消息對象類 類通過 二進制數(shù)組 寫 和 讀 消息類型
    • 使用方法包括:
    <-- 方式1:直接序列化和反序列化 消息 --> protocolBuffer.toByteArray()。 // 序列化消息 并 返回一個包括它的原始字節(jié)的字節(jié)數(shù)組 protocolBuffer.parseFrom(byte[] data); // 從一個字節(jié)數(shù)組 反序列化(解析) 消息<-- 方式2:通過輸入/ 輸出流(如網(wǎng)絡輸出流) 序列化和反序列化消息 --> protocolBuffer.writeTo(OutputStream output)。 output.toByteArray(); // 將消息寫入 輸出流 ,然后再 序列化消息 protocolBuffer.parseFrom(InputStream input)。 // 從一個 輸入流 讀取并 反序列化(解析)消息// 僅僅含包括字段的getters方法 // required string name = 1; public boolean hasName();// 假設字段被設置,則返回true public java.lang.String getName();// required int32 id = 2; public boolean hasId(); public int getId();// optional string email = 3; public boolean hasEmail(); public String getEmail();// repeated .tutorial.Person.PhoneNumber phone = 4; // 反復(repeated)字段有一些額外方法 public List<PhoneNumber> getPhoneList(); public int getPhoneCount(); // 列表大小的速記 // 作用:通過索引獲取和設置列表的特定元素的getters和setters

    經(jīng)常使用的如上,很多其它請看官方文檔

    3.1.2 Builder類

    作用:創(chuàng)建 消息構造器 & 設置/ 獲取消息對象的字段值 & 創(chuàng)建 消息類 實例

    屬于 消息對象類 的內(nèi)部類

    a. 創(chuàng)建 消息構造器

    Demo.Person.Builder person = Person.newBuilder();

    b. 設置/ 獲取 消息對象的字段值 詳細方法例如以下:

    // 標準的JavaBeans風格:含getters和setters // required string name = 1; public boolean hasName();// 假設字段被設置,則返回true public java.lang.String getName(); public Builder setName(String value); public Builder clearName(); // 將字段設置回它的空狀態(tài)// required int32 id = 2; public boolean hasId(); public int getId(); public Builder setId(int value); public Builder clearId();// optional string email = 3; public boolean hasEmail(); public String getEmail(); public Builder setEmail(String value); public Builder clearEmail();// repeated .tutorial.Person.PhoneNumber phone = 4; // 反復(repeated)字段有一些額外方法 public List<PhoneNumber> getPhoneList(); public int getPhoneCount(); // 列表大小的速記 // 作用:通過索引獲取和設置列表的特定元素的getters和setterspublic PhoneNumber getPhone(int index); public Builder setPhone(int index, PhoneNumber value);public Builder addPhone(PhoneNumber value); // 將新元素加入到列表的末尾public Builder addAllPhone(Iterable<PhoneNumber> value); // 將一個裝滿元素的整個容器加入到列表中 public Builder clearPhone();public Builder isInitialized() // 檢查全部 required 字段 是否都已經(jīng)被設置public Builder toString() : // 返回一個人類可讀的消息表示(用于調(diào)試)public Builder mergeFrom(Message other) // 將 其它內(nèi)容 合并到這個消息中,覆寫單數(shù)的字段,附接反復的。public Builder clear() // 清空全部的元素為空狀態(tài)。

    3.2 詳細使用

    • 使用過程例如以下:
      步驟1:通過 消息類的內(nèi)部類Builder類 構造 消息構造器
      步驟2:通過 消息構造器 設置 消息字段的值
      步驟3:通過 消息構造器 創(chuàng)建 消息類 對象
      步驟4:序列化 / 反序列化 消息

    • 詳細使用例如以下:(凝視非常清晰)

    public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 步驟1:通過 消息類的內(nèi)部類Builder類 構造 消息類的消息構造器Demo.Person.Builder personBuilder = Demo.Person.newBuilder();// 步驟2:設置你想要設置的字段為你選擇的值personBuilder.setName("Carson");// 在定義.proto文件時,該字段的字段修飾符是required,所以必須賦值personBuilder.setId(123);// 在定義.proto文件時,該字段的字段修飾符是required,所以必須賦值personBuilder.setEmail("carson.ho@foxmail.com"); // 在定義.proto文件時,該字段的字段修飾符是optional,所以可賦值 / 不賦值(不賦值時將使用默認值)Demo.Person.PhoneNumber.Builder phoneNumber = Demo.Person.PhoneNumber.newBuilder();phoneNumber.setType( Demo.Person.PhoneType.HOME);// 直接採用枚舉類型里的值進行賦值phoneNumber.setNumber("0157-23443276");// PhoneNumber消息是嵌套在Person消息里,能夠理解為內(nèi)部類// 所以創(chuàng)建對象時要通過外部類來創(chuàng)建// 步驟3:通過 消息構造器 創(chuàng)建 消息類 對象Demo.Person person = personBuilder.build();// 步驟4:序列化和反序列化消息(兩種方式)/*方式1:直接 序列化 和 反序列化 消息 */// a.序列化byte[] byteArray1 = person.toByteArray();// 把 person消息類對象 序列化為 byte[]字節(jié)數(shù)組System.out.println(Arrays.toString(byteArray1));// 查看序列化后的字節(jié)流// b.反序列化try {Demo.Person person_Request = Demo.Person.parseFrom(byteArray1);// 當接收到字節(jié)數(shù)組byte[] 反序列化為 person消息類對象System.out.println(person_Request.getName());System.out.println(person_Request.getId());System.out.println(person_Request.getEmail());// 輸出反序列化后的消息} catch (IOException e) {e.printStackTrace();}/*方式2:通過輸入/ 輸出流(如網(wǎng)絡輸出流) 序列化和反序列化消息 */// a.序列化ByteArrayOutputStream output = new ByteArrayOutputStream();try {person.writeTo(output);// 將消息序列化 并寫入 輸出流(此處用 ByteArrayOutputStream 取代)} catch (IOException e) {e.printStackTrace();}byte[] byteArray = output.toByteArray();// 通過 輸出流 轉(zhuǎn)化成二進制字節(jié)流// b. 反序列化ByteArrayInputStream input = new ByteArrayInputStream(byteArray);// 通過 輸入流 接收消息流(此處用 ByteArrayInputStream 取代)try {Demo.Person person_Request = Demo.Person.parseFrom(input);// 通過輸入流 反序列化 消息System.out.println(person_Request.getName());System.out.println(person_Request.getId());System.out.println(person_Request.getEmail());// 輸出消息} catch (IOException e) {e.printStackTrace();}} }

    Demo 地址

    Carson_Ho的Github :https://github.com/Carson-Ho/ProtocolBuffer

    高級功能

    • 貼心的Google還提供將Protocol Buff 編碼方式 轉(zhuǎn)化為 其它編碼方式,如 Json、XML等等

      即將 Protocol Buff 對象 轉(zhuǎn)化為其它編碼方式的數(shù)據(jù)存儲對象

    • 以下展示的是 將 Protocol Buff 對象 轉(zhuǎn)化為 Json對象

    // 步驟1:在Gradle加入依賴 compile 'com.googlecode.protobuf-java-format:protobuf-java-format:1.4'// 步驟2:將`Protocol Buff` 對象 序列化 為 `Json`對象 JsonFormat jsonFormat = new JsonFormat(); String person2json = jsonFormat.printToString(mProtoBuffer);

    6. 總結(jié)

    • 數(shù)據(jù)傳輸量較大的需求場景下,Protocol Buffer比XML、Json 更小、更快、使用 & 維護更簡單!

    • 以下用 一張圖 總結(jié)在 Android平臺中使用 Protocol Buffer 的整個步驟流程:

    • 看完本文,你應該會非常好奇為什么Protocol Buffer 的優(yōu)勢這么大:為什么序列化后的數(shù)據(jù)包比XML、Json更小、傳輸速度更快?
    • 下一篇文章我將對Protocol Buffer 進行源碼分析。有興趣能夠繼續(xù)關注我的CSDN博客!

    請幫頂或評論點贊!

    由于你的鼓舞是我寫作的最大動力!

    總結(jié)

    以上是生活随笔為你收集整理的快来看看Google出品的Protocol Buffer,别仅仅会用Json和XML了的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。