[Read binary file] - Last chunk of bytes read twice

Hi everyone, I wrote a template function for reading binary file. I also got a binary file which contains a sequence from 1 to 10 (int number). Assume that I don't know the length of the file, I am finding a way to make the reading loop stop after reading the last chunk of bytes. I know that doing this way will make the last number to be printed twice. Is there any solution to this problem? Thank you.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using namespace std;
void read_binary(istream& obj, Type& value)
{
	obj.read(reinterpret_cast<char*>(&value), sizeof(Type));
}


void main()
{
	ifstream file("data.txt", ios::binary);

	int i;
	while (!file.eof())
	{
		read_binary(file, i);
		cout << i;
	}

	file.close();
	cin.get();
}
Last edited on
As a general principle, avoid looping on eof.
The logic is incorrect, when the last block is read, the eof flag will not be set. it only is set after the next attempt to read the file - which of course fails, but the program does not check at that stage, so the previous existing value is used.
Try this instead. The body of the while loop is entered only after a successful read operation:
1
2
3
4
5
    
    while (read_binary(file, i))
    {
        cout << i;
    }

Oops! I overlooked that you use your own function. Change it to return a reference to the stream.
1
2
3
4
istream &  read_binary(istream& obj, Type& value)
{
    return obj.read(reinterpret_cast<char*>(&value), sizeof(Type));
}
Last edited on
I know that doing this way will make the last number to be printed twice. Is there any solution to this problem? Thank you.

Yes, either pre-fetch the first record, then move your function call to the last line of the while(), or change your function to return the stream and use the function call instead of the eof().
1
2
3
4
5
6
7
8
9
10
11
12
13
	ifstream file("data.txt", ios::binary);

	int i;

	read_binary(file, i);

	while (!file.eof())
	{
		cout << i;
	        read_binary(file, i);
	}

	// file.close(); ///// This is not needed just get rid of it, let the destructor do it's job. 


Or:
1
2
3
4
5
6
7
8
9
10
istream& read_binary(istream& obj, Type& value)
{
	obj.read(reinterpret_cast<char*>(&value), sizeof(Type));
        return obj;
}
...
	while (read_binary(file, i))
	{
		cout << i;
	}


I prefer the second way myself.

But be careful about that template function, remember if your "Type" has non-trivial member variables you can't use the read() function to read that "Type". And remember std::string is a non-trivial type, as are any pointers.

One other comment, not disagreeing,
Generally while (file) is more useful than while (!file.eof())
Agreed since while(file) will check for all stream errors not just eof().

Topic archived. No new replies allowed.