Problem reading/writing binary file.

I have a script that dumps class info into a binary file, then another script that retrieves it.

Since binary files only accept chars, I wrote three functions for reading and writing Short Ints, Ints, and Floats. I've been experimenting with them so they're not overloaded properly, but they all look like this:

1
2
3
4
5
6
7
8
void writeInt(ofstream& file, int val) {
	file.write(reinterpret_cast<char *>(&val), sizeof(val));
}
int readInt(ifstream& file) {
	int val;
	file.read(reinterpret_cast<char *>(&val), sizeof(val));
	return val;
}


I'll put the class load/save script at the end of the post, but I don't think it'll make too much sense without the rest of the class info.

Anyway, it seems that the file gets saved properly. It has the correct size, and all of the data matches when I load it. However, at some point in the load process, the file.read() function starts returning 0xCCCCCCCC every time. This looks to me like a read error, but I'm not sure why, or how to correct it. Since the file is the correct size, and I don't touch the seekg() function, it doesn't seem likely that it's reaching the end of file prematurely. I can only assume it's an issue with my read/write method, since I did kind of hack it together with limited knowledge. However, if this is the case, why does it read all the data up to a certain point without issue?

The error starts occurring at a random point each run. This may or may not be related to the fact that all the class data is randomly generated.

Does anyone have experience with this? I'm not even sure how to continue debugging it at this point.

Anyway, here are the load/save functions:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
    void saveToFile(string fileName) {
        ofstream dataFile(fileName.c_str());
        writeInt(dataFile, inputSize);
        writeInt(dataFile, fullSize);
        writeInt(dataFile, outputSize);
        // Skips input nodes - no data needs to be saved for them.
        for (int i = inputSize; i < fullSize; i++) {    // Saves each node after inputSize
            writeShortInt(dataFile, nodes[i].size);
            writeShortInt(dataFile, nodes[i].skip);
            writeFloat(dataFile, nodes[i].value);
            //vector<int> connects;
            //vector<float> weights;
            for (int j = 0; j < nodes[i].size; j++) {
                writeInt(dataFile, nodes[i].connects[j]);
                writeFloat(dataFile, nodes[i].weights[j]);
            }
        }
        read(500);
    }
    void loadFromFile(string fileName) {
        ifstream dataFile(fileName.c_str());
        inputSize = readInt(dataFile);
        fullSize = readInt(dataFile);
        outputSize = readInt(dataFile);
        nodes.resize(fullSize);

        for (int i = 0; i < inputSize; i++) {
            nodes[i].setSize(0);    // Sets input nodes
        }

        for (int i = inputSize; i < fullSize; i++) {    // Loads each node after inputSize
            int s = readShortInt(dataFile);
            nodes[i].setSize(s);
            nodes[i].skip = readShortInt(dataFile);
            nodes[i].value = readFloat(dataFile);
            //vector<int> connects;
            //vector<float> weights;
            for (int j = 0; j < nodes[i].size; j++) {
                nodes[i].connects[j] = readInt(dataFile);
                nodes[i].weights[j] = readFloat(dataFile);
            }
            read(i);
        }
        read(500);
    }


Thanks in advance!
What is your read(int) function doing? What is its purpose on line 42, since you don't have it in the corresponding place in your saveToFile() function.

I would suggest using a debugger, and stepping into each line of code to see when exactly it starts messing up. Also, I would add a if (!file) { cout << "error" << endl; } to the line after file.read(), to clearly be notified when it fails (for testing, in real code you'd do an exception or return false or something).

Another problem might be an error in copying and pasting, since you probably have duplicate/very similar code in your write/read<type> functions.

Templates can cut down on the code duplication.

1
2
3
4
5
6
template <typename T>
T readType(ifstream& file)
{
    T val;
    file.read(reinterpret_cast<char *>(&val), sizeof(T));
}
Last edited on
0xCCCCCCCC is a bit pattern used to initialize the stack, to locate uninitialized variables. It could be that the file is invalid, or that the data that was written to the file was uninitialized. With the information you have, there's no way of knowing, so start by adding a check to readInt():
1
2
3
4
5
6
7
int readInt(ifstream& file) {
	int val;
	file.read(reinterpret_cast<char *>(&val), sizeof(val));
	if (!file || file.gcount() < sizeof(val))
		throw std::runtime_error("Invalid file.");
	return val;
}
Ah, sorry, I missed that info.

The read(i) is just outputting the class info to the console. I used that to make sure the data is correct before the error occurs.

The error is happening at a random instance of line 39. It's visible through the read(i) function, since it outputs the bad data.
Helios, if (!file && file.gcount() < sizeof(val)) is definitely triggering, even with an '&&'. So does that mean the file's been closed or invalidated somehow, or could it mean I'm trying to read outside the file?
Interesting note: the readInt error always occurs after readFloat is called, so if there's an ifstream issue, it might be occurring there.

1
2
3
4
5
float readFloat(ifstream& file) {
	float val;
	file.read(reinterpret_cast<char *>(&val), sizeof(val));
	return val;
}
I posted on StackOverflow and somebody pointed out that I hadn't declared the files as binary. It's odd to me that it even partially worked! Anyway, it seems like it's functioning properly now, thanks for the help!
Topic archived. No new replies allowed.