【问题标题】:Marshall multiple protobuf to fileMarshall 将多个 protobuf 归档
【发布时间】:2010-08-18 14:16:53
【问题描述】:

背景:

我正在使用 Google 的 protobuf,我想使用 C++ 将数 GB 的 protobuf 编组数据读/写到文件中。由于建议将每个 protobuf 对象的大小保持在 1MB 以下,我认为写入文件的二进制流(如下图所示)会起作用。每个偏移量包含到下一个偏移量的字节数,直到到达文件末尾。这样一来,每个 protobuf 可以保持在 1MB 以下,我可以随心所欲地将它们 glob 在一起。

[int32 offset]
[protobuf blob 1]
[int32 offset]
[protobuf blob 2]
...
[eof]

我有一个可以在 Github 上运行的实现:

src/glob.hpp
src/glob.cpp
test/readglob.cpp
test/writeglob.cpp

但我觉得我写了一些糟糕的代码,希望能得到一些关于如何改进它的建议。因此,

问题:

  • 我正在使用reinterpret_cast<char*> 在二进制fstream 中读取/写入32 位整数。由于我使用的是 protobuf,所以我假设所有机器都是小端的。我还断言 int 确实是 4 个字节。 鉴于这两个限制性假设,是否有更好的方法将 32 位整数读/写到二进制 fstream
  • 在读取fstream 时,我创建了一个临时的固定长度char 缓冲区,这样我就可以将此固定长度缓冲区传递给protobuf 库以使用ParseFromArray 进行解码,因为ParseFromIstream 将消耗整个流。我真的更愿意告诉库最多从fstream 读取下一个N 字节,但protobuf 中似乎没有该功能。 传递fstream 的最多 N 个字节的函数的最惯用方法是什么?或者我的设计是否足够颠倒,我应该考虑完全不同的方法?

编辑:

  • @codymanix:我正在转换为char,因为如果我没记错的话,istream::read 需要一个char 数组。我也没有使用提取运算符>>,因为我读到它与二进制流一起使用的形式很差。还是这最后一条建议是假的?
  • @Martin York:删除new/delete 以支持std::vector<char>glob.cpp 现已更新。谢谢!

【问题讨论】:

  • 为什么要首先将 int 转换为 char*?

标签: c++ protocol-buffers


【解决方案1】:

不要使用 new []/delete[]。

取而代之的是,我们使用 std::vector 来保证在发生异常时释放。

不要假设读取​​会返回您请求的所有字节。
检查 gcount() 以确保你得到了你所要求的。

而不是让 Glob 根据构造函数中的开关实现输入和输出的代码。而是实现两个专门的类,如 ifstream/ofstream。这将简化界面和使用。

【讨论】:

  • 马丁-谢谢。我实施了前 2 个更改,我正在处理第 3 个更改。你对reinterpret_cast的使用有什么意见吗?鉴于 protobuf 的 ParseFromArray / ParseFromIstream 接口,您是否认为将 fstream 读入 std::vector 是最佳设计选择?
  • 在这种情况下,我个人对 reinterpret_cast 没有任何问题。我认为它有助于记录文档并为读者提供所需的信息,即这是一个危险的演员表。但是:我知道我在这个主题上属于少数派,大多数人会建议您使用 static_cast,因为它具有标准定义的含义,而 reinterpret_cast 是实现定义的。
  • 读入向量。我看不出你有任何选择。缺少分支您自己的协议缓冲区版本或(将适当的 API 更改接受到主分支中)。从消息中获取缓冲区并直接写入该缓冲区会很好(或为流读取 API 提供最大长度)。
  • 再次感谢!我还将 glob 分解为 iglob/oglob。这对我来说是一次很棒的学习经历,再次感谢您的宝贵时间!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-29
相关资源
最近更新 更多