技巧
您还可以将设计和使用问题发送到 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 内部从未使用过它。
此技术需要使用描述符支持动态消息。在使用自描述消息之前,请检查您的平台是否支持此功能。