Reputation: 10750
When I write a double to a filestream, then write an integer, the integer gets appended to the double as extra digits, and I have no idea why it happens. Could someone please explain this for me? Minimal example:
#include <iostream>
#include <fstream>
int main()
{
std::fstream s("test.bin", std::fstream::binary | std::fstream::trunc | std::fstream::in | std::fstream::out);
s << 3.14;
int n = 36;
s << n;
s.seekp(0);
double d;
s >> d;
printf("%f\n", d);
}
What I expect to happen:
3.14
to the file (8 bytes)36
to the file (4 bytes)3.140000
)What actually happens:
The program outputs 3.143600
- I have absolutely no idea why this happens. It makes zero sense. If I change the initial value, say from 3.14
to 18.3204
, then it outputs 18.320436
. What's happening?
Upvotes: 1
Views: 139
Reputation: 58947
It writes the value 3.14 to the file (8 bytes)
It writes the value 36 to the file (4 bytes)
This is not what happens. >>
and <<
and friends read and write values in human-readable form.
s << 3.14;
writes the digit 3, a full stop, the digit 1, and the digit 4 to the file (4 ASCII characters).
s << 36;
writes the digit 3, and the digit 6 to the file (2 ASCII characters).
The file then contains 6 ASCII characters: a 3, a full stop, a 1, a 4, a 3, and a 6. Or as any normal person would write it: it contains 3.1436
.
s >> d;
reads a number, by characters from the file until it finds a character that doesn't look like a number, and then converting the characters it read into a number (the same way they'd be converted if you typed them into cin
). It reads 3, full stop, 1, 4, 3, 6, and then produces the number 3.1436.
Upvotes: 2
Reputation: 33982
When operating on streams, <<
and >>
perform formatted access. Ignoring the behind -the-scenes voodoo, <<
writes strings and >>
reads strings. So
s << 3.14;`
turns 3.14 into a string and writes the string to the file. Same with s << n;
.
You now have a file containing the characters "3.1436".
s >> d;
reads the file as a string looking for separating whitespace or any other character that cannot be transformed into a double value. Since there is nothing separating 3.14 and 36 in the file, 3.1436 is read back in as a single number.
What you need to do is use raw, unformatted reads and writes:
#include <iostream>
#include <fstream>
int main()
{
std::fstream s("test.bin",
std::fstream::binary | std::fstream::trunc |
std::fstream::in | std::fstream::out);
double d = 3.14;
int n = 36;
if (s.write((char*) &d, sizeof(d)) &&
s.write((char*) &n, sizeof(n)))
{
s.seekp(0);
if (s.read((char*) &d, sizeof(d)))
{
std::cout << d;
}
else
{
std::cerr << "failed to read\n";
}
}
else
{
std::cerr << "failed to write\n";
}
}
Always test the IO to make sure it succeeded.
Also be warned that this isn't all that portable. A file written on one machine is not guaranteed to be readable on another without more care. int
s may be different sizes and Beware the endian my son! The order that bytes...
Upvotes: 0