file I/O question

J

John Ratliff

I'm trying to overload the << and >> operators to serialize a class to
disk. It writes things correctly, but it doesn't read them back correctly.

Can someone tell what I'm doing wrong? Here is an example demonstrating
my problem.

------- tmp.cc --------------
#include <cstdlib>
#include <ctime>
#include <fstream>
#include <iostream>

class foo {
private:
long keymap[5];
int joymap[5];
int joystick;
bool useJoystick, useDpad;

friend std::eek:stream &operator<<(std::eek:stream &, const foo &);
friend std::istream &operator>>(std::istream &, foo &);

public:
foo(bool init = true);
};

foo::foo(bool init) {
if (init) {
for (int i = 0; i < 5; i++) {
keymap = static_cast<long>(rand() % 1000);
joymap = rand() % 16;
}

joystick = -1;
useJoystick = useDpad = false;
}
}

std::eek:stream &operator<<(std::eek:stream &output, const foo &f) {
for (int i = 0; i < 5; i++) {
output << f.keymap;
output << f.joymap;
}

output << f.joystick << f.useJoystick << f.useDpad;

return output;
}

std::istream &operator>>(std::istream &input, foo &f) {
for (int i = 0; i < 5; i++) {
input >> f.keymap;
input >> f.joymap;
}

input >> f.joystick >> f.useJoystick >> f.useDpad;

return input;
}

int main(int, char **) {
srand(time(NULL));

foo f, f2(false);

std::fstream out("foo.bar",
std::ios_base::eek:ut | std::ios_base::binary);

if (!out) {
std::cerr << "fatal: unable to open foo.bar for writing\n";
return -1;
}

out << f;
out.close();

std::cout << "wrote the following to foo.bar...\n" << f << "\n\n";

std::fstream in("foo.bar",
std::ios_base::in | std::ios_base::binary);

if (!in) {
std::cerr << "fatal: unable to open foo.bar for reading\n";
return -1;
}

in >> f2;
in.close();

std::cout << "read the following from foo.bar...\n" << f2 << '\n';

return 0;
}
-----------------------------

This is the output I get with mingw/g++ 3.4.2

$ g++ -W -Wall -O2 tmp.cc
$ ./a.exe
wrote the following to foo.bar...
252694219161177692989-100

read the following from foo.bar...
-12009252579208987889302009252574400902539976962368368020092919242009145480255255

$ cat foo.bar
252694219161177692989-100

The data is being written correctly, I'm just not sure why I can't do
the reverse when I read it from the file.

Thanks,

--John Ratliff
 
R

red floyd

John said:
I'm trying to overload the << and >> operators to serialize a class to
disk. It writes things correctly, but it doesn't read them back correctly.

Can someone tell what I'm doing wrong? Here is an example demonstrating
my problem.

------- tmp.cc --------------
[redacted
std::eek:stream &operator<<(std::eek:stream &output, const foo &f) {
for (int i = 0; i < 5; i++) {
output << f.keymap;
output << f.joymap;
}

output << f.joystick << f.useJoystick << f.useDpad;

return output;
}

std::istream &operator>>(std::istream &input, foo &f) {
for (int i = 0; i < 5; i++) {
input >> f.keymap;
input >> f.joymap;
}

input >> f.joystick >> f.useJoystick >> f.useDpad;

return input;
}

[redacted]


You might want to put some spaces in there. Remember, just 'cause you
opened it up in binary mode, doesn't mean the data you put out using
"<<" is. It has to do with newline translations. So when you output
the members of f, it puts them out in ASCII.

That is,

if all member variables of f are 0 (hypothetical), you'll get the
following output:

0000000000000

How is the input parser supposed to know where each field begins?

Try:

std::eek:stream& operator<<(std::eek:stream& os, const foo& f)
{
for (int i = 0; i < 5 ; ++i)
os << f.keymap << " " << f.joymap << " ";
os << f.joystick << " "
<< f.useJoystick << " "
<< f.useDpad << std::endl;
return os;
}

Now, you have the following outputs (again, assuming all 0)

0 0 0 0 0 0 0 0 0 0 0 0 0

So the input parser can determine where each field begins. Note that I
put an 'endl' after the last value.
 
J

John Ratliff

red said:
John said:
I'm trying to overload the << and >> operators to serialize a class to
disk. It writes things correctly, but it doesn't read them back
correctly.

Can someone tell what I'm doing wrong? Here is an example
demonstrating my problem.

------- tmp.cc --------------
[redacted
std::eek:stream &operator<<(std::eek:stream &output, const foo &f) {
for (int i = 0; i < 5; i++) {
output << f.keymap;
output << f.joymap;
}

output << f.joystick << f.useJoystick << f.useDpad;

return output;
}

std::istream &operator>>(std::istream &input, foo &f) {
for (int i = 0; i < 5; i++) {
input >> f.keymap;
input >> f.joymap;
}

input >> f.joystick >> f.useJoystick >> f.useDpad;

return input;
}

[redacted]



You might want to put some spaces in there. Remember, just 'cause you
opened it up in binary mode, doesn't mean the data you put out using
"<<" is. It has to do with newline translations. So when you output
the members of f, it puts them out in ASCII.

That is,

if all member variables of f are 0 (hypothetical), you'll get the
following output:

0000000000000

How is the input parser supposed to know where each field begins?

Try:

std::eek:stream& operator<<(std::eek:stream& os, const foo& f)
{
for (int i = 0; i < 5 ; ++i)
os << f.keymap << " " << f.joymap << " ";
os << f.joystick << " "
<< f.useJoystick << " "
<< f.useDpad << std::endl;
return os;
}

Now, you have the following outputs (again, assuming all 0)

0 0 0 0 0 0 0 0 0 0 0 0 0

So the input parser can determine where each field begins. Note that I
put an 'endl' after the last value.


I was thinking along those lines, but I wasn't sure.

Yeah, I know binary mode only means newline translation, but for some
reason I thought it would add terminators or spaces for me. Don't know
why I had that thought.

Thanks,

--John Ratliff
 
M

mlimber

John said:
I'm trying to overload the << and >> operators to serialize a class to
disk. It writes things correctly, but it doesn't read them back correctly.

Can someone tell what I'm doing wrong? Here is an example demonstrating
my problem.
[snip]

The data is being written correctly, I'm just not sure why I can't do
the reverse when I read it from the file.


If you look, I bet you'll find that the data in the file is in text
format, not binary. That's because the default stream insertion (<<)
and extraction (>>) operators are for formatted (i.e., text-mode) I/O
only, and I believe they force the file mode to text, no matter what
you opened it as. Use ostream::write() and istream::read() in your
operator functions instead of the standard insertion/extraction
operators to read and write in non-text format. You should probably
also check in your operator functions to see if the file is in binary
mode or not.

Alternately, use text mode and separate the values with spaces. This
might yield smaller files if your numbers are generally small: a binary
integer of value 2 would take up four bytes whereas the text version
would take up 2 (one for the text digit, one for the space). Using hex
might also help if the numbers are unsigned.

Cheers! --M
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,990
Messages
2,570,211
Members
46,796
Latest member
SteveBreed

Latest Threads

Top