【问题标题】:Protocol buffers issue, multiple serializations into a binary file协议缓冲区问题,多次序列化为二进制文件
【发布时间】:2011-12-01 17:44:58
【问题描述】:

我从 protobuf 二进制文件 io 中得到了一些奇怪的行为。我正在将文本语料库预处理为 protobuf 中间文件。我的序列化类如下所示:

  class pb_session_printer
  {
  public:
    pb_session_printer(std::string & filename)
      : out(filename.c_str(), std::fstream::out | std::fstream::trunc | 
                              std::fstream|binary)
      {}

    void print_batch(std::vector<session> & pb_sv)
    {
      boost::lock_guard<boost::mutex> lock(m);

      BOOST_FOREACH(session & s, pb_sv)
      {
        std::cout << out.tellg() << ":";
        s.SerializeToOstream(&out);
        out.flush();
        std::cout << s.session_id() << ":" << s.action_size() << std::endl;
      }
      exit(0);
    }

    std::fstream out;
    boost::mutex m;
  };

输出的 sn-p 看起来像:

0:0:8
132:1:8
227:2:6
303:3:6
381:4:19
849:5:9
1028:6:2
1048:7:18
1333:8:28
2473:9:24

第一个字段显示序列化正在正常进行。

当我运行加载程序时:

int main()
{
  std::fstream in_file("out_file", std::fstream::in | std::ios::binary);
  session s;

  std::cout << in_file.tellg() << std::endl;
  s.ParseFromIstream(&in_file);
  std::cout << in_file.tellg() << std::endl;
  std::cout << s.session_id() << std::endl;

  s.ParseFromIstream(&in_file);
}

我明白了:

0
-1
111
libprotobuf ERROR google/protobuf/message_lite.cc:123] Can't parse message of type 
"session" because it is missing required fields: session_id

session_id : 111 是流末尾的条目,我显然不了解库的二进制 io 工具的语义。请帮忙。

【问题讨论】:

    标签: c++ boost protocol-buffers std


    【解决方案1】:

    如果您在单个文件中写入多个 protobuffer,您将需要写入 protobuf + protobuffer 的大小并分别读取它们(因此没有 ParseFromIstream 就像 Cat Plus Plus 提到的那样)。当你读入 protobuffer 后,你可以用 ParseFromArray 解析它。

    您的文件看起来会这样大小(空格只是为了便于阅读):

    size protobuf size protobuf size protobuf 等

    【讨论】:

      【解决方案2】:

      Message::ParseFromIstream is documented 消耗整个输入。由于您要序列化一系列相同类型的消息,因此您只需使用该类型的 repeated 字段创建一条新消息,然后使用它。

      【讨论】:

      • 是的,我读到了,也让我感到疑惑。文本语料库是 17gigs,有 3.4 亿行 :(,你的建议意味着整个语料库需要一口气记住,不是吗?
      • @HassanSyed:可能。另一种选择是实现自己的解析函数,一次只使用一条消息。
      • 有趣的是它遍历了流中早期的所有“会话”,最后只返回会话 111。我原以为它会读取第一个会话并将文件头移到末尾。
      • 是的,我想我可以创建一个以换行符分隔的 SerializeToString() 版本。这在过去对我有用,如果我可以保持二进制,它似乎更“干净”。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-08-26
      • 2017-05-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多