技术

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

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

常见文件名后缀

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

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

特别是对于文本格式,.textproto 也相当常见,但我们建议使用 .txtpb,因为它更简洁。

流式传输多个消息

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

大型数据集

Protocol Buffers 并非旨在处理大型消息。作为一般经验法则,如果您处理的消息每个都大于 1 MB,则可能需要考虑其他策略。

也就是说,Protocol Buffers 非常适合处理大型数据集中的单个消息。通常,大型数据集是由许多小片段组成的,每个小片段都是结构化数据。即使 Protocol Buffers 无法一次处理整个集合,使用 Protocol Buffers 编码每个片段也会大大简化您的问题:现在您只需要处理一组字节字符串而不是一组结构。

Protocol Buffers 没有包含对大型数据集的任何内置支持,因为不同的情况需要不同的解决方案。有时简单的记录列表就足够了,而其他时候您则需要类似数据库的东西。每个解决方案都应作为单独的库开发,以便只有需要它的人才需要承担成本。

自描述消息

Protocol Buffers 不包含其自身类型的描述。因此,仅给定一个原始消息,而没有定义其类型的相应 .proto 文件,则很难提取任何有用的数据。

但是,.proto 文件的内容本身可以使用协议缓冲区表示。源代码包中的文件 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 内部使用过它。

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