技巧
您也可以将设计和使用问题发送到 Protocol Buffers 讨论组。
常见文件名后缀
将消息以多种不同格式写入文件是相当常见的做法。我们建议为这些文件使用以下文件扩展名。
| 内容 | 扩展名 |
|---|---|
| 文本格式 | .txtpb |
| Wire 格式 | .binpb |
| JSON 格式 | .json |
具体到文本格式,.textproto 也相当常见,但我们推荐使用 .txtpb,因为它更简洁。
流式传输多条消息
如果您想将多条消息写入单个文件或流中,您需要自行记录一条消息的结束位置和下一条消息的开始位置。Protocol Buffer 的 wire 格式不是自定界的,因此协议缓冲区解析器无法自行确定消息的结束位置。解决此问题的最简单方法是在写入每条消息之前,先写入该消息的大小。当您读回消息时,先读取大小,然后将相应字节数读入一个单独的缓冲区,再从该缓冲区进行解析。(如果您想避免将字节复制到单独的缓冲区,可以查看 C++ 和 Java 中的 CodedInputStream 类,它可以被告知将读取限制在一定的字节数内。)
大数据集
Protocol Buffers 并非设计用于处理大型消息。根据经验,如果您处理的消息大小超过 1MB,可能就该考虑其他策略了。
话虽如此,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 内部从未有过使用它的需求。
此技术需要支持使用描述符的动态消息。在使用自描述消息之前,请检查您的平台是否支持此功能。