C++ protobuf:如何通过 "SerializeToOstream()" 将多条消息写入文件

C++ protobuf: how to write multiple messages into file by "SerializeToOstream()"

我发现当我使用SerializeToOstream()时,只有最后一条消息被写入文件,之前的消息都被后面的调用覆盖了。像这样:

我有我的 hello.proto:

message hello
{
    required int32 f1=1;
    required int32 f2=2;
    optional int32 f3=3;
}

然后我把它编译并用在一个cpp文件中:

#include "hello.pb.h"
#include<fstream>
#include<iostream>
using namespace std;
int main()
{
    fstream fo("./hello.data",ios::binary|ios::out);
    hello p1,p2,p3;
    p1.set_f1(1);
    p1.set_f2(2);
    p2.set_f1(3);
    p2.set_f2(4);
    p3.set_f1(5);
    p3.set_f2(6);
    p1.SerializeToOstream(&fo);
    p2.SerializeToOstream(&fo);
    p3.SerializeToOstream(&fo);
    fo.close();

    fstream fi("./hello.data",ios::binary|ios::in);
    hello pi;
    pi.ParseFromIstream(&fi);
    cout<<pi.f1()<<pi.f2()<<endl;
    return 0;
}

嗯,我发现只有 "p3" 被写入此 "hello.data",p1 和 p2 以某种方式被覆盖了?

为什么protobuf只写最后一条消息?我们通常使用 protobuf 来传递多条消息,对吧?那么如何将多条消息写入一个文件呢?如何更正我的程序?

这里的问题是协议缓冲区不是自定界的;要解析一条消息,您必须事先知道要读取多少字节。由于有线格式的工作方式,您可以连接两个(或更多)序列化的协议缓冲区,并且仍然有一个有效的消息;对于任何给定的单数字段,后面的值优先于前面的值。所以发生的事情是 ParseFromIstream 正在读取所有三个序列化消息,就好像它们是一条消息一样,最后一条消息实际上优先于前两条消息。

要解决此问题,您必须为每条消息添加某种消息长度前缀。通常,这是通过在每条消息前加上 varint storing its length. This code 前缀来完成的,Kenton Varda 是一个很好的例子,说明了如何在 C++ 中做到这一点。