将对象向量保存到C++中的文件中

Saving vector of objects to file in C++

本文关键字:文件 C++ 对象 向量 保存      更新时间:2023-10-16

我想将对象向量保存到文件中。最有效的方法是什么?我应该在程序启动时加载整个矢量,在本地对其进行操作,然后在程序退出时保存它,或者每次需要更改矢量内部的内容时访问文件吗?

此外,是否可以一次保存整个向量,或者我需要逐个保存元素?

如果您的数据是POD(因此每个元素的大小相同),您可以使用以下思想。如果没有,下面的想法可能很难轻易使用。

以下代码显示您可以使用"ostream::write"将二进制数据放入文件中。矢量<>承诺对象在内存中是从前到后(或从后到前,根据您的意愿)的,因此它们排列整齐,相对紧凑,便于传输。

使用"istream::read"读回内存也是类似的。但在这里,您需要首先分配缓冲区。

在下面的代码中,我分配了6个对象进行写入,然后找到向量内存的开头,并用一个"写入"将所有6个对象写入。

在读取过程中,我实例化了6个对象并将其加载到一个新的向量中(注意,向量提供了一种使用默认ctor分配和实例化对象的切片器方法)。

如何将对象的数量从写入工作传递到读取?这可以根据文件大小来计算。(见统计)

使用重新解释的强制转换是不可接受的,并且可能不可移植。但有时你只能这么做。

希望这种"邪恶"会促使人们做出更好的选择。

我在一些调试std::cout中离开了。。。希望你觉得它们有帮助。

edit-4/8-在某种程度上清除了代码

       // create a vector of 6 clear elements to save to file
       std::vector<Something>  vec6W(6);  // default ctor clears contents
       // change several elements by init'ing them
       vec6W[0].init();
       //   [1] is clear (all 0's)
       vec6W[2].init();
       vec6W[3].init();
       //   [4] is clear (all 0's)
       vec6W[5].init();
       std::cout << "                vec6W.size(): " << vec6W.size()      << std::endl; // 6
       std::cout << "               sizeof(vec6W): " << sizeof(vec6W)     << std::endl; // 12
       std::cout << "           sizeof(something): " << sizeof(Something) << std::endl; // 100
       std::cout << "            sizeof(vec6W[3]): " << sizeof(vec6W[3])  << std::endl; // 100
       //                        #elements      bytes per element
       std::streamsize nBytes = (vec6W.size() * sizeof(Something));
       std::cout << "                     nBytes : " << nBytes  << std::endl;  // 600
       // simulate a file using
       std::stringstream ss;
       // note size
       std::cout << "             ss.str().size(): " << ss.str().size() << std::endl;    // 0
       // identify address of 1st element of vector
       // cast to a 'const char*' for 'write()' method
       const char* wBuff = reinterpret_cast<const char*>(&vec6W[0]);
       // report address
       std::cout << " static_cast<const void*>(wBuff): " << std::hex
                 <<   static_cast<const void*>(wBuff)    << std::dec << std::endl;
       //write vector to ss
       ss.write(wBuff, nBytes);
       std::cout << "n  note ss content size change " << std::endl;
       std::cout << "            ss.str().size() : " << ss.str().size() << std::endl;
       // //////////////////////////////////////////////////////////////////
       // build a vector of 6 clear elements to create buffer for read from file
       std::vector<Something>  vec6R(6);
       // identify address of 1st element of vector
       std::cout << "                  &vec6R[0] : " << std::hex <<  (&vec6R[0]) << std::dec  << std::endl;
       char* rBuff = reinterpret_cast<char*>(&vec6R[0]);
       // read vector from ss
       (void)ss.read(rBuff, nBytes); // read back same number of bytes
       // //////////////////////////////////////////////////////////////////
       // confirm vec6R matches what was written vec6W
       int diff = memcmp(wBuff, rBuff, nBytes);
       std::cout << (diff ? "FAILED" : "wBuff MATCHES rBuff: SUCCESS") << std::endl;
       // now consider comparing vec6R to vec6W element by element

当类具有虚拟方法时,可能会出现其他问题。

祝你好运。

编辑-----

指针是可以处理的,但会产生额外的工作量和一些不对称性。

相关的工作可以称为"持久存储"。

此外,还有一些工具可以简化非POD数据的附加步骤(对不起,我忘记了名称。)

这个问题没有单一的答案。

适当的方法取决于应用程序的需要、保存文件的原因以及对文件的处理方法。例如,打算在另一个程序中打开并被人类理解的文件可能与仅保存程序状态的文件(即,只有软件程序需要理解它)写得非常不同。

效率最高取决于你对效率的衡量。一些可能的衡量标准包括写入速度、读取速度、文件大小、进行写入的代码大小等。并非所有这些因素都结合在一起——例如,存档程序可能会选择慢速方法来写入文件,以实现快速读取速度。

通常,编写一个对象集合需要单独编写所有对象,再加上一些额外的记账(例如,首先输出对象的数量),尤其是在以后需要读取文件的情况下。然而,更聪明的算法可能会从一组对象中导出某种汇总数据。例如,假设一个向量按顺序包含整数1到20。一种写入方式是写入全部20个值。另一种是简单地发出字符串"1-20"。