C++:当数据复杂时,读/写二进制数据到文件

3

如果我需要定义如何保存数据,我要如何以二进制形式读取/写入文件?

我试图将一些简单的数据结构以二进制形式保存到文件中。

例如,我有一个结构体向量,就像这样:

struct Vertex
{
    x;
    y;
    z;
}

std::vector<Vertex> vertices;

我想将这个向量以二进制形式保存到文件中。
我知道如何使用ifstreamostream输出它,使用<<>>运算符可以重载来处理我的数据,但它们无法输出二进制数据。
我也知道如何使用.write()以二进制形式写入,但问题在于我找不到一种方法来重载我需要的内容,以便处理我的数据。
3个回答

2

这是一个类似问题的答案。虽然在您的情况下这样做没问题,但请注意,如果您在结构体中使用指针,这种方式将不起作用。

指针表示:“此其他内存段中加载了相关数据”,但实际上,它仅包含内存的地址。然后,写操作将保存此内存位置。当您重新加载时,很有可能内存仍然不包含您想要的信息。

通常人们会创建序列化机制。向您的结构体添加一个方法或编写另一个函数,该函数以您的结构体作为参数并输出包含以您决定的特殊格式的数据的char*数组。您还需要相反的函数从文件中读取并从二进制数据重新创建结构体。您应该查看boost::serialization,它处理这个非常常见的编程问题。


可能不是。您不应尝试序列化未明确为此目的而创建的类。相反,您应该为保存创建数据格式。例如,文件中的第一个int将是记录数,后跟实际记录。 - Eric
我将使用BOOST::Serialization,因为我可以看到它在未来会很有用。由于Boost文档非常混乱,我以前一直避免使用它。如果其他人看到了这篇文章,我建议在这里查看更易于跟随的指南:http://www.ocoudert.com/blog/2011/07/09/a-practical-guide-to-c-serialization/ - user947871

1

有一种方法可以实现(不一定是最好的方法),就是使用任何二进制写入函数来编写数据,例如:

write(fd,data,size);

但是将“数据”作为结构传递。
例如
Vertex data;
data.x = 0;
etc...
write(fd,(char*)&data,sizeof(data));

这将把结构体视为字符数组,并将它们写入文件。反过来读取应该与上述过程相反。

请注意,使用向量(动态分配并可能在内存中具有奇怪的位置)没有真正好的方法,因此我建议使用结构体数组。


是的。这是我推荐的。 - rspencer

0

我一直在寻找一种高效且紧凑的方式来永久存储数据,但是并没有找到任何可执行的最小示例,所以我为您整理了一下。

这个解决方案的美妙之处在于能够随意处理 'vector' 中的数据,并且可以根据需要扩展 'struct'(只需做出微小的更改)

这样,在内存中表示的 'vector' 通过 'std::vector' 提供的 'data()' 方法传输到驱动器上,然后再传回来。

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#define FILENAME "data.bin"

struct Vertex
{
    size_t x{};
    size_t y{};
    std::string z{};
};

void writeVectorToBinary(std::vector<Vertex> &v);
void readVectorFromBinary(std::vector<Vertex> &v);
void printVector(std::vector<Vertex> &v);

int main()
{
std::vector<Vertex> vertices;
vertices.push_back({1,2,"three"});
vertices.push_back({4,5,"six"});

writeVectorToBinary(vertices);
printVector(vertices);
readVectorFromBinary(vertices);
printVector(vertices);

std::cin.get();
return 0;
}


void writeVectorToBinary(std::vector<Vertex> &v)
{
  size_t size = v.size();
  //Open Binary file, to write out data
  std::ofstream file(FILENAME, std::ios::binary);
  if(!file)
    std::cout << "Something went wrong" << std::endl;
  //Store/Write the vector size
  file.write(reinterpret_cast<const char*>(&size), sizeof(size));
  //Store/Write the data of the vector out
  file.write(reinterpret_cast<const char*>(v.data()), sizeof(v[0])*size);
  //Close binary file
  file.close();
}

void readVectorFromBinary(std::vector<Vertex> &v)
{
//Clear Vector just for the proof of concept
v.clear();
size_t size{};
//Open Binary file to read in data
std::ifstream file(FILENAME,std::ios::binary);
if(!file)
  std::cout << "Something went wrong" << std::endl;
//Read the vector size
file.read(reinterpret_cast<char*>(&size), sizeof(size));
//Resize vector now that its known
v.resize(size);
//Read vector data in
file.read(reinterpret_cast<char*>(v.data()), sizeof(v[0])*size);
//Close binary file
file.close();
}

void printVector(std::vector<Vertex> &v)
{
  for(size_t i{}; i < v.size(); ++i ){
    std::cout << "\n------Vector" << i << "--------" << std::endl;
    std::cout << v[i].x << std::endl;
    std::cout << v[i].y << std::endl;
    std::cout << v[i].z << std::endl;
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接