Search code examples
filec++11structbinarybinaryfiles

Read/Write binary file using struct in struct


I need to create a binary file and write the current state of the struct created.

This struct have a other struct. Something like this :

struct A {
    bool flag=true;
    int n;
};

struct B
{
    int n1;
    A *array;
};

How write all in the binary file?

But specially how read from the binary file and load all in the struct B again, and then load all in A *array.

Thanks a lot.

I tried this way, but sometime give me a exception and block all (violation of read access).

HOW WRITE :

ofstream save("binary.bin", ios::binary);
    if (!save) {
        cerr << "Error creation file ";
    }
    else {
        save.write(reinterpret_cast<char*>(&prova), sizeof(prova));
    }

    binary.close();

HOW READ and PRINT:

save.read(reinterpret_cast<char*>(&prova), sizeof(prova));
for (size_t i = 0; i != try.n1; ++i)
   {
   cout << "....." << try.n1 <<endl;
   cout << "..... "<< try.array[i].n <<" ";
   cout << ".....: "<<try.array[i].flag<< endl;
  }

Solution

  • Writting a single instance of A in binary is simple since its a POD type:

    std::ofstream outfile = {...};
    A a = { ... };
    outfile.write(reinterpret_cast<char const*>(&a), sizeof(a));
    

    Writing a single instance of B, OTOH, is not as simple. You'll have to write n1 first and then the elements from the array.

    B b = { ... };
    
    // Write the number of elements first.
    outfile.write(reinterpret_cast<char const*>(&b.n1), sizeof(b.n1));
    
    // Now write the elements.
    outfile.write(reinterpret_cast<char const*>(b.array), sizeof(A)*b.n1);
    

    Reading from a binary file is, obviously, the inverse of that. Reading to an instance of A is simple.

    std:ifstream infile = { ... };
    
    A a;
    infile.read(retinterpret_cast<char*>(&a), sizeof(a));
    

    Reading to an instance of B is a little bit more involved. You'll have to read the size first, then allocate memory for the elements of the array, and then read the elements of the array.

    B b;
    
    // Read the number of elements
    infile.read(retinterpret_cast<char*>(&b.n1), sizeof(b.n1));
    
    // Allocate memory for the elements of the array.
    b.array = new A[b.n1];
    
    // Now read the elements of the array.
    infile.read(retinterpret_cast<char*>(b.array), sizeof(A)*b.n1);
    

    You can simplify some of that code by using helper functions that reduce the use of retinterpret_cast all over your code.

    namespace MyApp
    {
       template <typename T>
       std::ostream& write(std::ostream& out, T const& pod)
       {
          out.write(reinterpret_cast<char const*>(&pod), sizeof(T));
          return out;
       }
    
       template <typename T>
       std::ostream& write(std::ostream& out, T* array, int numElements)
       {
          out.write(reinterpret_cast<char const*>(array), sizeof(T)*numElements);
          return out;
       }
    
       template <typename T>
       std:istream read(std::istream& in, T& pod)
       {
          in.read(reinterpret_cast<char*>(&pod), sizeof(T));
          return in;
       }
    
       template <typename T>
       std:istream& read(std:istream& in, T* array, int numElements)
       {
          in.read(reinterpret_cast<char*>(array), sizeof(T)*numElements);
          return in;
       }
    }
    

    Now, you can use:

    // Write a
    MyApp::write(outfile, a);
    
    // Read a
    MyApp::read(infile, a);
    
    // Write b
    MyApp::write(outfile, b.n1);
    MyApp::write(outfile, b.array, b.n1);
    
    // Read b
    MyApp::write(infile, b.n1);
    b.array = new A[b.n1];
    MyApp::write(infile, b.array, b.n1);