技巧

描述了一些處理 Protocol Buffers 的常用設計模式。

您還可以將設計和使用問題傳送到 Protocol Buffers 討論組

常用檔名字尾

將訊息寫入不同格式的檔案是很常見的。我們建議對這些檔案使用以下副檔名。

內容副檔名
文字格式.txtpb
線纜格式.binpb
JSON 格式.json

對於文字格式,.textproto 也相當常見,但我們建議使用 .txtpb 以求簡潔。

流式傳輸多個訊息

如果您想將多個訊息寫入單個檔案或流,您需要自己跟蹤一個訊息在哪裡結束,下一個訊息在哪裡開始。Protocol Buffer 線纜格式不是自定界的,因此 protocol buffer 解析器無法自行確定訊息的結束位置。解決此問題最簡單的方法是在寫入訊息本身之前寫入每個訊息的大小。當您讀回訊息時,您會先讀取大小,然後將位元組讀入單獨的緩衝區,然後從該緩衝區進行解析。(如果您想避免將位元組複製到單獨的緩衝區,請檢視 CodedInputStream 類(C++ 和 Java 均有),該類可以被告知將讀取限制在一定數量的位元組內。)

大資料集

Protocol Buffers 並非旨在處理大型訊息。通常,如果您的訊息大小超過 1 兆位元組,可能需要考慮採用其他策略。

話雖如此,Protocol Buffers 非常適合處理大型資料集中的單個訊息。通常,大型資料集是小片段的集合,每個小片段都是結構化資料。儘管 Protocol Buffers 無法一次處理整個資料集,但使用 Protocol Buffers 對每個片段進行編碼可以大大簡化您的問題:現在您只需要處理一組位元組字串而不是一組結構體。

Protocol Buffers 不包含任何內建的對大型資料集的支援,因為不同情況需要不同的解決方案。有時一個簡單的記錄列表就足夠了,而另一些時候您可能需要更像資料庫的東西。每個解決方案都應該開發為單獨的庫,以便只有需要它的人才需要支付成本。

自描述訊息

Protocol Buffers 不包含對其自身型別的描述。因此,如果只給出一個原始訊息而沒有定義其型別的相應 .proto 檔案,很難提取任何有用的資料。

但是,.proto 檔案的內容本身可以使用 protocol buffers 來表示。原始碼包中的檔案 src/google/protobuf/descriptor.proto 定義了涉及的訊息型別。protoc 可以使用 --descriptor_set_out 選項輸出一個 FileDescriptorSet(表示一組 .proto 檔案)。有了這個,您可以定義一個自描述的協議訊息,如下所示:

syntax = "proto3";

import "google/protobuf/any.proto";
import "google/protobuf/descriptor.proto";

message SelfDescribingMessage {
  // Set of FileDescriptorProtos which describe the type and its dependencies.
  google.protobuf.FileDescriptorSet descriptor_set = 1;

  // The message and its type, encoded as an Any message.
  google.protobuf.Any message = 2;
}

透過使用 DynamicMessage 等類(C++ 和 Java 中可用),您可以編寫能夠操作 SelfDescribingMessage 的工具。

儘管如此,此功能未包含在 Protocol Buffer 庫中的原因是我們在 Google 內部從未使用過它。

此技術需要使用描述符支援動態訊息。在使用自描述訊息之前,請檢查您的平臺是否支援此功能。