Saving object to file, and then loading it

Hi guys,

Could someone please tell me why my code is not working?

Interface
1
2
3
4
5
6
7
8
9
10
11
12
13

class Person{

private:
	char name[80];
	short age;
	

public:
	void get_data();
	void show_data();
};


Implementation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "player.h"
#include <iostream>

using namespace std;

void Person::get_data(){

	cout<<"Enter name: ";cin>>name;
	cout<<"Enter age: ";cin>>age;

}
void Person::show_data(){
	
	cout<<"Name: "<<name<<endl;
	cout<<"Aage: "<<age<<endl;

}



Main

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
#include <fstream>
#include <iostream>

#include "player.h"

using namespace std;

int main(){

	char dummy;
	char choice;
	Person person,saved_person;

	ofstream output_file("C:/Users/Mike/Desktop/test/save.dat",ios::binary);
	ifstream input_file("C:/Users/Mike/Desktop/test/save.txt",ios::binary);

	cout<<"'1' to save\n"
		<<"'2' to load\n"
		<<":->";
	cin>>choice;

	if(choice=='1'){

		person.get_data();
		output_file.write(reinterpret_cast<char*>(&person),sizeof(person));
		exit(1);
	}

	if(choice=='2'){

		cout<<"The following information has been saved\n\n";

		input_file.read(reinterpret_cast<char*>(&person),sizeof(person));

		saved_person.show_data();
	}
	cin>>dummy;
	
	return 0;
}


This is a simple example from and old Lafore C++ book, with a few tweaks by me. The point is simple. Save object person to a *.dat file, exit the program, then start up program again, open up *.dat file, and load contents.

The first problem is the compiler is printing a bunch of Asian characters to the file (is this normal?)

The second problem is, it's not loading the object as it should, giving me a bunch of gibberish.

Thanks for all and any help!

Mike
1
2
3
4
5
cout<<"The following information has been saved\n\n";

input_file.read(reinterpret_cast<char*>(&person),sizeof(person));

saved_person.show_data();


Above, you're reading person from the file but you're calling saved_person.show_data.

Also as an aside, the above binary file I/O is not guaranteed to work by the standard because Person is not a simple aggregate.

It would be guaranteed to work if Person was a simple struct, i.e.

1
2
3
4
5
struct Person
{
   char name[80];
   short age;
};


Also, I would suggest when you have time to look into Endianness and how it affects file I/O.
Last edited on
Hi Shacktar,

I did try it with person.show_data() and it did not work, gave me the same gibberish.

I did not try using a struct, as classes are so much more useful.

Thanks,

Mike
Just, to get things straight, you're writing to save.dat, then changing its extension and reading from save.txt, correct?

Maybe the problem is that name is not null terminated. Try making a constructor for person and zeroing out name. i.e.

1
2
3
4
Person::Person()
{
   memset(name, 0, sizeof(name)); //will work because name is an array
}


I did not try using a struct, as classes are so much more useful.

I was just saying that writing the whole class instance at once to a file is not guaranteed to work. You could for instance make WriteFile and LoadFile methods that save/load the members one at a time.
Last edited on
Hi Shacktar,

Yeah, those methods, "WriteFile" and "LoadFile" are the next step, but I was hoping to make this work.

As for the extensions, that was just me trying both *.dat and *.txt, but when both the input and output are the same extension, the problem exists.

I will try it with your constructor.

Thanks,

Mike
Using

1
2
3
4
5
6
7

Person::Person()
{
   memset(name, 0, sizeof(name)); //will work because name is an array
}



did not work.


Mike
Can we see the new code? If you're leaving the extension the same, are you sure you're not overwriting the file with this line?

ofstream output_file("C:/Users/Mike/Desktop/test/save.dat",ios::binary);
Hi Shacktar,

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

#include <fstream>
#include <iostream>

#include "player.h"

using namespace std;

int main(){

	char dummy;
	char choice;
	Person person,saved_person;

	ofstream output_file("C:/Users/Mike/Desktop/test/save.dat",ios::binary);
	ifstream input_file("C:/Users/Mike/Desktop/test/save.dat",ios::binary);

	cout<<"'1' to save\n"
		<<"'2' to load\n"
		<<":->";
	cin>>choice;

	if(choice=='1'){

		person.get_data();
		output_file.write(reinterpret_cast<char*>(&person),sizeof(person));
		exit(1);
	}

	if(choice=='2'){

		cout<<"The following information has been saved\n\n";

		input_file.read(reinterpret_cast<char*>(&person),sizeof(person));

		person.show_data();
	}
	cin>>dummy;
	
	return 0;
}


This is more or less as it appears in the book. But I still get gibberish written to either *.dat file or *.txt. It does not matter which one I choose. And of course when I read it back in, it's nonsense.

Thanks,

Mike
How about closing the file and removing the exit call on write?

1
2
3
output_file.write(reinterpret_cast<char*>(&person),sizeof(person));
exit(1);
output_file.close();
You're not checking the file handles' validity.

Probably you're not even able to open a file with write permissions, and open again the same file with read permissions.

You should move ofstream and ifstream lines where they are actually located at.

This method is also called Lazy Processing, which is a program's speed optimization.
Topic archived. No new replies allowed.