Protobuf可以进行部分读取吗?

5
我希望将我的地形数据保存到文件中,并仅加载其中的一部分,因为它太大了,无法完全存储在内存中。实际上,我甚至不知道protobuf是否适合此目的。
例如,我会有一个类似这样的结构(语法可能不正确,我只知道简单的基础知识):
message Quad {
    required int32 x = 1;
    required int32 z = 2;

    repeated int32 y = 3;
}
xz值在我的程序中可用,我想通过使用它们来查找具有相同xz(在文件中)的正确Quad对象,以获得y值。但是,我不能仅使用ParseFromIstream()解析文件,因为(我认为)它会将整个文件加载到内存中,而在我的情况下,文件太大了。
那么,protobuf能否加载一个对象,将其发送给我进行检查,如果对象不正确,则给我第二个对象?
实际上...我可以问一下: ParseFromIstream()是否会将整个文件加载到内存中?

6
@infact这是一个毫无根据的评论,需要进行某种形式的限定,比如你觉得它在哪方面失败了。 - Marc Gravell
2个回答

4

虽然一些库允许您部分读取文件,但Google推荐的技术是将文件简单地组成多个消息:

https://developers.google.com/protocol-buffers/docs/techniques

协议缓冲区不适用于处理大型消息。一般而言,如果您处理的是每个超过1兆字节的消息,则可能是时候考虑另一种策略了。

尽管如此,协议缓冲区非常适用于处理大数据集中的单个消息。通常,大数据集实际上只是由小块数据组成的集合,其中每个小块数据可以是结构化数据。

因此,您可以仅通过长度分隔的Quad消息的长序列将其写入文件。如果您需要随机查找特定的Quad,则可能需要添加某种索引。


2
这取决于你使用的实现方式。有些实现方式有“按顺序读取”的API。例如,假设你将其存储为“重复的Quad”,那么使用protobuf-net就应该是这样的:
int x = ..., y = ...;
var found = Serializer.DeserializeItems<Quad>(source)
            .Where(q => q.x ==x && q.y == y);

重点是:它会产生一个缓冲(不是一次性全部加载)和短路序列。
我不熟悉C++ API,但我希望它有类似的功能。如果最坏情况下没有,您可以解析varint头并准备一个长度限制的流。

嗨,我正在阅读您的其他答案,我认为它们与我的问题相似,但我想知道是否使用protobuf对我有意义。目前,我的数据是纯文本“[x z] y y y y y.....”,下一行再次是[x1 z1] y1 y1 y1 y1...等等。在这种情况下,protobuf序列化会使文件更小吗? - tobi
哦,我找到了一个好答案 https://dev59.com/x2w05IYBdhLWcg3wiybg ,y 值的范围在 0 到 255 之间(其中许多将接近 ~127),因此它看起来可以很好地进行压缩。 - tobi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接