我正在使用谷歌协议缓冲区来序列化股票市场数据(即时间戳,出价,询问字段)。 我可以将一条消息存储到一个文件中并对其进行反序列化而不会出现问题。
如何将多条消息存储到一个文件中?不知道如何分隔消息。我需要能够动态地将新消息附加到文件中。
答案 0 :(得分:28)
我建议在writeDelimitedTo(OutputStream)
个对象上使用parseDelimitedFrom(InputStream)
和Message
方法。 writeDelimitedTo
在消息本身之前写入消息的长度; parseDelimitedFrom
然后使用该长度只读取一条消息而不再读取消息。这允许将多个消息写入单个OutputStream
,然后单独解析。有关详细信息,请参阅https://developers.google.com/protocol-buffers/docs/reference/java/com/google/protobuf/MessageLite#writeDelimitedTo(java.io.OutputStream)
答案 1 :(得分:12)
来自文档:
http://code.google.com/apis/protocolbuffers/docs/techniques.html#streaming
流式传输多条消息
如果要将多条消息写入单个文件或流,请执行此操作 由你来跟踪一条消息的结束和下一条消息的结束 开始。协议缓冲区有线格式不是自定界限的,所以 协议缓冲区解析器无法确定消息在其上的结束位置 拥有。解决此问题的最简单方法是写入大小 在编写消息本身之前的每条消息。当你读到的时候 回来的消息,你读取大小,然后将字节读入a 单独的缓冲区,然后从该缓冲区解析。 (如果你想避免 将字节复制到单独的缓冲区,请查看CodedInputStream class(在C ++和Java中),可以告诉它将读取限制为a 一定数量的字节。)
答案 2 :(得分:6)
Protobuf每个最外层记录不包含终止符,因此您需要自己执行此操作。最简单的方法是在数据前加上后面记录的长度。就个人而言,我倾向于使用编写字符串标题的方法(对于任意字段编号),然后将长度作为“varint” - 这意味着整个文档本身就是一个有效的protobuf,并且可以作为对象使用然而,使用“重复”元素,只需一个固定长度(通常是32位小端)标记也可以。对于任何此类存储,它可以根据您的需要进行附加。
答案 3 :(得分:4)
如果您正在寻找C ++解决方案,Kenton Varda submitted a patch to protobuf around August 2015会增加对writeDelimitedTo()和readDelimitedFrom()调用的支持,这些调用将以某种方式将一系列原型消息序列化/反序列化到文件中这与这些调用的Java版本兼容。不幸的是,这个补丁还没有被批准,所以如果你想要这个功能,你需要自己合并它。
另一个选择是谷歌通过其他项目开源的protobuf文件读/写代码。例如,or-tools库包含将原型流序列化/反序列化为文件的类RecordReader和RecordWriter。
如果你想要几乎没有外部依赖关系的这些类的独立版本,我有一个or-tools的fork只包含这些类。请参阅:https://github.com/moof2k/recordio
使用这些类进行读写非常简单:
File* file = File::Open("proto.log", "w");
RecordWriter writer(file);
writer.WriteProtocolMessage(msg1);
writer.WriteProtocolMessage(msg2);
...
writer.Close();
答案 4 :(得分:-4)
更简单的方法是对每条消息进行base64编码,并将其作为每行记录存储。