Bob
Bob

Reputation: 327

Saving an array to file in C++

I have a custom class called Array. It stores the array of type T and a size integer.

Does this look right saving an array to file?

fout.write((char *)m_array, sizeof(T) * m_size);

How I'm storing it:

    bool save(const std::string &filename)
    {
        std::ofstream fout;

        // Open the file.
        fout.open(filename, std::ios::out | std::ios::binary);

        // Validate that the file is open.
        if (!fout.is_open())
            return false;

        // Write the size to file.
        fout << m_size << std::endl;  

        fout.write((char *)m_array, sizeof(T) * m_size);

        fout.close();

        return true;
    }

Load function:

    bool load(const std::string &filename)
    {
        std::ifstream fin;
        int size = 0;

        // Open the file.
        fin.open(filename, std::ios::in | std::ios::binary);

        // Validate that the file is open.
        if (!fin.is_open())
            return false;

        // Read the size from file.
        fin >> size;

        // Resize if needed
        if (size != m_size)
            resize(size); 

        fin.read((char *)m_array, sizeof(T) * m_size);

        fin.close();

        return true;
    }

The main file:

Array<int> a(10);

a.clear(); // set all values to 0. 

a[5] = 3; 

if (a.save("test.dat"))
    con.writeLine("Saved");

This gives the output values 0,0,0,0,0,0,3,0,0,0.

But on retrieval, using this:

fin.read((char *)m_array, sizeof(T) * m_size);

I'm getting 10,0,0,0,0,768,0,0,0,0.

What am I doing wrong? The second parameter says it wants the count, which would be sizeof(T) * m_size to me.

Update: The alternative is this on saving:

for (int i = 0; i < m_size; i++)
fout << m_array[i] << std::endl;

But I prefer the first method.

Upvotes: 1

Views: 5726

Answers (1)

Jonathan Mee
Jonathan Mee

Reputation: 38919

You're mixing formatted and unformatted writes to the stream. Rather than:

fout << m_size << std::endl;

You need to do:

fout.write(reinterpret_cast<char*>(&m_size), sizeof(m_size));

EDIT:
After seeing you're update you'll need to read, not with this:

fin >> size;

But with this:

fin.read(reinterpret_cast<char*>(&m_size), sizeof(m_size));

So it should be mentioned here that you're reinventing the wheel. As long as you're OK with this... None the less I think it's appropriate here for me to suggest using vector<T>. It would make your code more readable, less error prone, and potentially faster.

Given vector<int> a you can write to ofstream fout like this:

const auto a_size = size(a);

fout.write(reinterpret_cast<const char*>(&a_size), sizeof(a_size));
fout.write(reinterpret_cast<const char*>(data(a)), sizeof(decltype(a)::value_type) * a_size);

Given ifstream fin, you can read like this:

size_t a_size;

fin.read(reinterpret_cast<char*>(&a_size), sizeof(a_size));
a.resize(a_size);
fin.read(reinterpret_cast<char*>(data(a)), sizeof(decltype(a)::value_type) * a_size);

Live Example

Upvotes: 4

Related Questions