-1

I'm trying to read an array object (Array is a class I've made using read and write functions to read and write from binary files. So far the write functions works but it won't read from the file properly for some reason. This is the write function :

void writeToBinFile(const char* path) const
    {
        ofstream ofs(path, ios_base::out | ios_base::app | ios_base::binary);
        if (ofs.is_open())
        {
            ostringstream oss;
            for (unsigned int i = 0; i < m_size; i++)
            {
                oss << ' ';
                oss << m_data[i];
            }
            ofs.write(oss.str().c_str(), oss.str().size());
        }
    }

This is the read function :

void readFromBinFile(const char* path)
    {
        ifstream ifs(path, ios_base::in | ios_base::binary || ios_base::ate);
        if (ifs.is_open())
        {
            stringstream ss;
            int charCount = 0, spaceCount = 0;
            ifs.unget();
            while (spaceCount != m_size)
            {
                charCount++;
                if (ifs.peek() == ' ')
                {
                    spaceCount++;
                }
                ifs.unget();
            }
            ifs.get();
            char* ch = new char[sizeof(char) * charCount];
            ifs.read(ch, sizeof(char) * charCount);
            ss << ch;
            delete[] ch;
            for (unsigned int i = 0; i < m_size; i++)
            {
                ss >> m_data[i];
                m_elementCount++;
            }
        }
    }

those are the class fields :

T* m_data;
unsigned int m_size;
unsigned int m_elementCount;

I'm using the following code to write and then read (1 execution for reading another for writing):

Array<int> arr3(5);
    //arr3[0] = 38;
    //arr3[1] = 22;
    //arr3[2] = 55;
    //arr3[3] = 7;
    //arr3[4] = 94;
    //arr3.writeToBinFile("binfile.bin");
    arr3.readFromBinFile("binfile.bin");
    for (unsigned int i = 0; i < arr3.elementCount(); i++)
    {
        cout << "arr3[" << i << "] = " << arr3[i] << endl;
    }

The problem is now at the readFromBinFile function, it get stuck in an infinite loop and peek() returns -1 for some reason and I can't figure why. Also note I'm writing to the binary file using spaces to make a barrier between each element so I would know to differentiate between objects in the array and also a space at the start of the writing to make a barrier between previous stored binary data in the file to the array binary data.

dikson231
  • 201
  • 5
  • 10
  • @JoachimPileborg I don't use it on the binary file itself – dikson231 Oct 04 '14 at 21:46
  • Why are you calling `unget` before you even start to read anything? – Some programmer dude Oct 04 '14 at 21:47
  • 1
    In the read function, you have this: `ss << ch;` Probably you intended `ss >> ch;`? – Boris Dalstein Oct 04 '14 at 21:48
  • Also, in the loop counting characters, you are also calling `unget` even when you haven't read anything. And the [`peek`](http://en.cppreference.com/w/cpp/io/basic_istream/peek) call will be called on the first byte in the file and only the first byte in the file, it will not advance the input pointer. – Some programmer dude Oct 04 '14 at 21:49
  • Why not write the number of elements at the top of the file, that way you don't have to read it twice. – Jonathan Potter Oct 04 '14 at 21:57
  • you cannot use ' ' as a delimiter in a binary file. int 32 == space – pm100 Oct 04 '14 at 21:58
  • @JoachimPileborg to read 1 character before reading the EOF char – dikson231 Oct 04 '14 at 21:59
  • @Boris no, I output char into ss and then input ss into the array and I use the delimiter "space" because I've read that when inputing from string stream it'll input from the current gpos until the next space – dikson231 Oct 04 '14 at 22:00
  • apparently I forgot ios_base::ate in the read binary file, posted an older version of what I had, updated – dikson231 Oct 04 '14 at 22:02
  • @pm100 I know 32 == space but why can't I use ' ' as a delimiter in a binary file ? when I wrote the data it wrote it to the file with the space and numbers no problems, could u explain ? – dikson231 Oct 04 '14 at 22:07
  • Possible duplicate of [How do you serialize an object in C++?](http://stackoverflow.com/questions/523872/how-do-you-serialize-an-object-in-c) – jww Oct 04 '14 at 22:16
  • @jww the answer given are is external APIs and the other answer that is given a solution not good enough for a reason he mentioned already, how this is duplicate ? – dikson231 Oct 04 '14 at 23:42

1 Answers1

1

The major problem, in my mind, is that you write fixed-size binary data in variable-size textual form. It could be so much simpler if you just stick to pure binary form.

Instead of writing to a string stream and then writing that output to the actual file, just write the binary data directly to the file:

ofs.write(reinterpret_cast<char*>(m_data), sizeof(m_data[0]) * m_size);

Then do something similar when reading the data.


For this to work, you of course need to save the number of entries in the array/vector first before writing the actual data.

So the actual write function could be as simple as

void writeToBinFile(const char* path) const
{
    ofstream ofs(path, ios_base::out | ios_base::binary);
    if (ofs)
    {
        ofs.write(reinterpret_cast<const char*>(&m_size), sizeof(m_size));
        ofs.write(reinterpret_cast<const char*>(&m_data[0]), sizeof(m_data[0]) * m_size);
    }
}

And the read function

void readFromBinFile(const char* path)
{
    ifstream ifs(path, ios_base::in | ios_base::binary);
    if (ifs)
    {
        // Read the size
        ifs.read(reinterpret_cast<char*>(&m_size), sizeof(m_size));

        // Read all the data
        ifs.read(reinterpret_cast<char*>(&m_data[0]), sizeof(m_data[0]) * m_size);
    }
}

Depending on how you define m_data you might need to allocate memory for it before reading the actual data.


Oh, and if you want to append data at the end of the array (but why would you, in the current code you show, you rewrite the whole array anyway) you write the size at the beginning, seek to the end, and then write the new data.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • in other question of mine I used a similar technique just writing the whole object http://stackoverflow.com/questions/26196682/c-reading-and-writing-objects-to-binary-files?noredirect=1#comment41078380_26196682 Is there a difference besides that you're writing the fields as char pointers rather than the object itself ? – dikson231 Oct 04 '14 at 22:03
  • @dikson231 When you say "writing the whole object", do you mean a complete instance of a class? If so then you need to be careful, because if the class contains pointers that will not work, and if the class contains a virtual table (i.e. if your class or a parent class, has virtual functions) then it wont work very well either. – Some programmer dude Oct 04 '14 at 22:06
  • yea that's what I meant, so in your solution it'll work ? Also couple of questions regarding your implementation, isn't static_cast is used to cast between pointers type ? Also I know it's off-topic question but any difference between c++ style cast to C style cast (char*) ? And using sizeof(m_data[0]) won't return you the size of a single object in the array ? don't you need writing sizeof(m_data) to get the size of the whole array ? – dikson231 Oct 04 '14 at 22:18
  • @dikson231 Regarding the `sizeof` thing, since I don't know what `m_data` is, using `sizeof(m_data[0]) * m_size` is safe. What if `m_data` is a `std::vector`? Or a pointer? Then `sizeof(m_data)` will not work. – Some programmer dude Oct 04 '14 at 22:29
  • so I followed your implementation and when I print the array it prints other numbers (all elements holds the same value) – dikson231 Oct 04 '14 at 23:20
  • Could you help me with this ? It doesn't work as I said above ^ – dikson231 Oct 05 '14 at 13:24