技术

描述了一些处理 Protocol Buffers 的常用设计模式。

您还可以将设计和使用问题发送到 Protocol Buffers 讨论组

常用文件名后缀

以几种不同的格式将消息写入文件是很常见的。我们建议对这些文件使用以下文件扩展名。

内容扩展名
文本格式.txtpb
线路格式.binpb
JSON 格式.json

对于文本格式,`.textproto` 也相当常见,但为了简洁起见,我们建议使用 `.txtpb`。

流式传输多个消息

如果要将多个消息写入单个文件或流,则需要您自己跟踪一个消息在哪里结束以及下一个消息在哪里开始。Protocol Buffer 线路格式不是自定界的,因此协议缓冲区解析器无法自行确定消息在哪里结束。解决此问题的最简单方法是在写入消息本身之前写入每个消息的大小。当您读回消息时,您读取大小,然后将字节读取到单独的缓冲区中,然后从该缓冲区解析。(如果您想避免将字节复制到单独的缓冲区,请查看 `CodedInputStream` 类(在 C++ 和 Java 中都有),该类可以被告知将读取限制为一定数量的字节。)

大型数据集

Protocol Buffers 不适合处理大型消息。作为一般的经验法则,如果您处理的消息每个都大于兆字节,那么可能是时候考虑替代策略了。

话虽如此,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 内部从未使用过它。

此技术需要使用描述符对动态消息的支持。在使用自描述消息之前,请检查您的平台是否支持此功能。