Question

How would I write/read data to a file in binary, if I also have to define how to save my data?
I'm attempting to save some simple data structures out to a file in binary.

For example, I have a vector of structs like this:

struct Vertex
{
    x;
    y;
    z;
}

std::vector<Vertex> vertices;

I want to save this vector out to a file in binary.

I know how to output it using ifstream and ostream using the << and >> operators, which can be overloaded to handle my data, but they can't output binary.

I also know how to use .write() to write in binary, but the issue there is that I can't find a way to overload what I need, in order to handle my data.

Was it helpful?

Solution

Here is an answer to a similar question. While this is ok in your case, be aware that if you are using pointers in your struct, this will not work.

The pointer means : "There is relevant data loaded in this other memory segment", but really, it only contains the address of the memory. Then the write operation will save this memory location. When you will load it back, there is very little chance that the memory still holds the information you want.

What people usually do is create a serialization mechanism. Add a method to your struct, or write another function that takes your struct as a parameter and outputs a char* array containing the data in a special format you decide. You will also need the opposite function to read from a file and recreate a struct from binary data. You should take a look at boost::serialization which handles this very common programming problem.

OTHER TIPS

One way of doing it (not necessarily the best) is to write the data, using whatever binary write function you choose, eg

write(fd,data,size);

But pass the "data" as the struct.

eg

Vertex data;
data.x = 0;
etc...
write(fd,(char*)&data,sizeof(data));

which will treat the struct as an array of characters, and then write them to the file. Reading it back in should be the reverse of the above.

Note that there is not really a nice way to do this with vectors (which are dynamically allocated and my have strange things in strange places in memory), so I recommend an array of structs.

I was looking for an efficient and compact way to store data permanently but wasn't able to find any executable minimal example so I put it together for you.

The beauty of this solution is the ability to handle the data in the 'vector' as it pleases and to expand the 'struct' as it pleases (with minor changes)

That way the 'vector' as represented in the memory is transferred to the drive and back again with the 'data()' method 'std::vector' is providing.

#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;
  }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top