在 java 中部分读取原型而不是完全解析

Read proto partly instead of full parsing in java

我以前定义了一个proto文件,例如

option java_package = "proto.data";
message Data {
    repeated string strs = 1;
    repeated int ints = 2;
}

我从网络收到了这个对象的输入流(或字节)。然后,通常,我会进行 Data.parserFrom(stream)Data.parserFrom(bytes) 之类的解析以获取对象。

因此,我只需要旅行时就必须在数据对象上保留全部内存 对象中的所有字符串和整数值。当对象尺寸很大时很糟糕。

遇到这个问题我该怎么办?

不幸的是,无法只解析 protobuf 的一部分。如果你想确定你已经看到 strsallintsall,你必须解析整个消息,因为值可以以任何顺序出现,甚至可以交错出现。

如果您只关心内存使用情况而不关心 CPU 时间,那么理论上您可以使用手写解析器来解析消息并忽略您不关心的字段。你仍然需要做解析的工作,你可以立即丢弃它们而不是将它们保留在内存中。但是,要做到这一点,您需要研究 Protobuf wire format 并编写您自己的解析器。你可以使用 Protobuf 的 CodedInputStream class 但是很多工作仍然需要手动完成。 Protobuf 库确实不是为此而设计的。

如果您愿意考虑使用不同的协议框架,Cap'n Proto 在设计上与 Pr​​otobufs 极其相似,但具有只读取您关心的消息部分的能力。 Cap'n Proto 不会对您不检查的字段产生任何开销,显然除了接收原始消息字节的带宽和内存。如果您正在从文件读取,并且您使用内存映射(MappedByteBuffer in Java),那么只有您实际使用的消息部分会从磁盘读取。

(披露:我是大多数 Google Protobufs v2(您可能正在使用的版本)以及 Cap'n Proto 的作者。)

嗯。看起来它可能已经实施但没有充分记录。 你测试过了吗?

参见讨论: https://groups.google.com/forum/#!topic/protobuf/7vTGDHe0ZyM

另请参阅 google 的 github 中的示例测试代码: https://github.com/google/protobuf/blob/4644f99d1af4250dec95339be6a13e149787ab33/java/src/test/java/com/google/protobuf/lazy_fields_lite.proto