【问题标题】:binary read/write arbitrary std::vector<std::vector<int> > in c++在 C++ 中二进制读/写任意 std::vector<std::vector<int> >
【发布时间】:2011-05-27 12:36:05
【问题描述】:

, 我想将二进制 std::vector&lt;std::vector&lt;int&gt; &gt; 对象 MATRIX 存储在文件中。

out.write((char*)&MATRIX, sizeof(MATRIX));

问题是,只有列尺寸是固定的。行维度发生变化。 如果我从二进制文件中读取对象,仅知道大小是不够的,不是吗?因此,初始化例如第二个矩阵与

std::vector<std::vector<int> > MATRIX2;
for ( int i=0;i<column_dim;i++ ) MATRIX2.push_back ( vector<int> ( 0 ) );
ifstream in(cstr, ios::in | ios::binary);

并使用

读取对象数据
ifstream in(cstr, ios::in | ios::binary);    
in.read((char*)& MATRIX2, fSize);

没有意义,因为编译器不知道保存数据的结构。 我的问题: 有没有比将矩阵结构(关于行尺寸的所有信息)保存在第二个文件中,读取它并创建一个具有适当结构的 MATRIX2 更好的方法来解决这个问题,然后使用

ifstream in(cstr, ios::in | ios::binary);    
in.read((char*)&nn_H_test, fSize);

?

【问题讨论】:

  • 文件格式是否给定?如果不是,也许你想看看boost.org/doc/libs/1_46_1/libs/serialization/doc/index.html。这应该使您可以很容易地存储和加载 int 矩阵。
  • 扩展我在stackoverflow.com/questions/3438132/…中建议的协议,在每个存储的矩阵前多加一个size_t来指定第一个维度。
  • 哎呀,您是否要转储文件中的原始std::vector?这将永远起作用,并且读回来你会得到一个处于完全混乱状态的对象(唯一正确的可能是向量大小,但指向元素的内部指针将是无效的) .您需要适当的序列化。
  • “那永远行不通”不是真的。如果我生成一个与 MATRIX 具有相同结构的 MATRIX2 对象,则所有内容都会以正确的顺序复制。
  • 你很幸运,一般来说,像这样将 std::vector 转储到文件会导致转储其私有成员,通常是向量大小、向量容量和 指针 到它使用的内存。因此,如果您在同一执行过程中转储并重新加载它,它可能会起作用,但如果您尝试在新进程中加载​​它,则会以无效的内部指针结束。

标签: c++ vector binary-data


【解决方案1】:

我将为您提供一个简短的示例,说明如何使用 boost 执行此操作。

#include <iostream>
#include <fstream>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

std::vector<std::vector<int > > g_matrix;
int main(int argc, char* argv[])
{
    // fill the vector
    std::ofstream ofs("c:\\dump");
    boost::archive::text_oarchive to(ofs);
    to << g_matrix;

    g_matrix.clear();
    std::ifstream ifs("c:\\dump");
    boost::archive::text_iarchive infs(ifs);
    infs >> g_matrix;
    // check your vector. It should be the same
}

如果您需要它更易于阅读,您也可以尝试从 boost 中提取 xml。
一如既往,不要重新发明轮子。

【讨论】:

    【解决方案2】:

    ios::binary 是almost certainly NOT going to have the result you think it will have - 它只影响行尾翻译。

    其次,如果您想在读取时恢复结构,您不会逃避必须存储内部向量的各个长度。像您现在尝试的那样将原始 std::vector 从流直接恢复到新的 std::vector 永远不会起作用。

    但是,结构化恢复并不难,只需存储每个内部向量的值的数量,然后是所有值。然后,您的读取例程可以安全地读取第一个值,然后读取 N 个下一个值,并假设之后的第一个值是下一行的值的数量。

    【讨论】:

    • 感谢您的评论。对于您的第一句话:您会建议什么?
    • 如果您想将向量存储为真正的“二进制”数据(例如,将磁盘上的 4 个字节用于 4 字节整数),您应该考虑使用流读写来编写自定义二进制文件流。
    【解决方案3】:

    对于一些非常简单的事情,为什么不在矩阵输出之前放置一个标题值来指定行列大小?简单的例子:

    4,2 //#rows, #columns
    0 1
    2 0
    2 3
    4 5
    

    现在当你读入矩阵时,先读入标题信息,然后再读入矩阵数据。

    如果您希望矩阵可序列化,您应该查看矩阵结构的序列化范例。在C++ FAQ 中阅读有关序列化的更多信息。

    【讨论】:

    • 谢谢,是的,这也是我想到的第一件事,但它有一个缺点:我的一些算法已经使用了这个矩阵,我不得不重写它们——不幸的是这会导致添加额外文件的工作更多。
    • 如果这是一个问题,那么序列化可能是您的解决方案。这样它就完全包含在矩阵中了。
    猜你喜欢
    • 2020-01-26
    • 1970-01-01
    • 1970-01-01
    • 2022-01-03
    • 2014-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-13
    相关资源
    最近更新 更多