Protocol buffers Google协议缓冲区-将消息存储到文件中

Protocol buffers Google协议缓冲区-将消息存储到文件中,protocol-buffers,Protocol Buffers,我使用谷歌协议缓冲区来序列化股票市场数据(即时间戳、出价、询问字段)。 我可以将一条消息存储到一个文件中并对其进行反序列化,而不会出现问题 如何将多条消息存储到一个文件中?我不知道怎样才能把这些信息分开。我需要能够动态地将新消息附加到文件中。Protobuf不包括每个最外层记录的终止符,因此您需要自己执行此操作。最简单的方法是在数据前面加上后面记录的长度。就我个人而言,我倾向于使用编写字符串头的方法(对于任意字段号),然后将长度作为“变量”——这意味着整个文档本身就是一个有效的protobuf,

我使用谷歌协议缓冲区来序列化股票市场数据(即时间戳、出价、询问字段)。 我可以将一条消息存储到一个文件中并对其进行反序列化,而不会出现问题


如何将多条消息存储到一个文件中?我不知道怎样才能把这些信息分开。我需要能够动态地将新消息附加到文件中。

Protobuf不包括每个最外层记录的终止符,因此您需要自己执行此操作。最简单的方法是在数据前面加上后面记录的长度。就我个人而言,我倾向于使用编写字符串头的方法(对于任意字段号),然后将长度作为“变量”——这意味着整个文档本身就是一个有效的protobuf,并且可以作为一个具有“重复”元素的对象使用,但是,只有一个固定长度(通常为32位小端点)标记也可以。对于任何此类存储,都可以根据需要进行附加。

来自文档:

流式传输多条消息

如果要将多条消息写入单个文件或流,则 由您来跟踪一条消息的结尾和下一条消息的结尾 开始。协议缓冲区连线格式不是自定界的,因此 协议缓冲区解析器无法确定消息在其 拥有解决此问题的最简单方法是写入 在您编写消息之前,请先阅读每条消息。当你读报纸的时候 返回消息时,您读取大小,然后将字节读入 分离缓冲区,然后从该缓冲区解析。(如果你想避免 将字节复制到单独的缓冲区,请检查CodedInputStream 类(在C++和java中),可以被告知将读取限制为 一定数量的字节。)


一种更简单的方法是对每条消息进行base64编码,并将其存储为每行记录。

我建议在
消息
对象上使用
writeDelimitedTo(OutputStream)
parseDelimitedFrom(InputStream)
方法
writeDelimitedTo
在消息本身之前写入消息的长度
parseDelimitedFrom
然后使用该长度仅读取一条消息,不再读取。这允许将多条消息写入单个
OutputStream
,然后分别进行解析。有关更多信息,请参阅< /P> < P>如果您正在寻找C++解决方案,Kuton瓦尔达将添加对RealDeLeIdEDTO()和RealDelimeDeFo()的支持,这些调用将以与这些调用的java版本兼容的方式将/从文件中序列化/反序列化原始消息序列。不幸的是,这个补丁还没有被批准,所以如果你想要这个功能,你需要自己合并它

另一个选择是谷歌有开源的protobuf文件,通过其他项目读/写代码。例如,库包含将原型流序列化/反序列化为文件的类和

如果您希望这些类的独立版本几乎没有外部依赖关系,我有一个只包含这些类的分支或工具。见:

使用这些课程进行阅读和写作非常简单:

File* file = File::Open("proto.log", "w");
RecordWriter writer(file);
writer.WriteProtocolMessage(msg1);
writer.WriteProtocolMessage(msg2);
...
writer.Close();

在这一切之后,我发现CSV最终变小了!可能是因为大多数时候我的数字都是一个字符。嗨,马克,你能详细说明一下“字符串头”的概念吗?@AntonioD所说的“字符串头”,我指的是字符串和其他子数据使用的“长度分隔”编码(导线类型2)。基本上:选择你的任意字段号,左移3“,或”2(导线类型),并对结果进行可变编码(这是protobuf中表示字段标题的标准过程)。因此,如果您的任意字段是
1
,您只需在前面加上10/0x0A即可。谢谢您,Marc,这正是我想要的。要将多个protobuf消息写入流/文件,请将您的输出流包装成CodeDoutpStream
CodeDoutpStream writer=CodeDoutpStream.newInstance(outputStreamToWrite);writer.writeRawVarint32(字节.长度);writer.writeRawBytes(字节)
读取整个文件:
CodedInputStream is=CodedInputStream.newInstance(InputStreamToRap);而(!is.isattend()){int size=is.readRawVarint32();YourMessage.parseFrom(is.readRawBytes(size);}
@Anony Mousse:如果你在一个文件/流中写入超过1条顶级消息,那么如果没有分隔符,阅读就不起作用。请参阅Marc Gravel的公认答案,base64的编码/解码开销可能无法实现protobuf快速和小型化的目的。我不确定——我本人对protobuf的世界来说是相当陌生的。它们是否具有同等功能在C++中,看起来这一直都是(至少在java实现中)。它在2009的这个Rev中:@安德烈霍特。C++等价物是由原BuffC++ C++库的作者提供的。