Writing/reading class object to/from file

I have successfully stored an object that contains strings and numerical values in a file, but when I try to read and display from file the stored strings are not displayed, while the numerical are displayed just fine. Why is that?
Write
1
2
3
4
5
6
string filename = "employee1.txt";
 
ofstream outfile;
outfile.open (filename.c_str(), ios::out | ios::app);
outfile.write ( (char *)(&employee), sizeof(employee) );
outfile.close();

Read
1
2
3
4
5
6
7
8
9
ifstream infile;
infile.open (filename.c_str(), ios::in);

while( infile.read ( (char *)&employee, sizeof(employee) ) )
infile.close();

cout << employee.m_Name;
cout << employee.m_id;
cout << employee.m_Age;


Last edited on
Will you give the full code


ofstream myfile;
myfile.open ("example.bin", ios::out | ios::app | ios::binary);




the line 5 of your write looks suspiciously wrong. both the cast and the sizeof. but since i don't know what the type of employee is I can't tell
Last edited on
Sorry fot the delay

The full code is too long because I use yes_no functions, other functions to modify and display the variables. Also instead of system("pause") I use a function I had seen in a Duoas post, but I use system() now because it's shorter. However I'll post the most important parts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <string>
#include <fstream>
#include <windows.h>

class Employee
{
public:
   string m_Name;
   string m_Gender;
   string m_Address;
   int m_id;
   int m_Age;
   int m_Phone;
   int m_Salary;
   int m_Department;
}


I create a new object

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int main()
{  
   Employee employee1;
   
   create_new_employee(employee1);
   
   string filename = "employee_test.txt";

   ofstream outfile;
   outfile.open (filename.c_str(), ios::out|ios::binary|ios::app);
   outfile.write ( (char *)(&employee1), sizeof(Employee) );
   outfile.close();

   system("pause");
   return 0;
}


When void create_new_employee(Employee& employee1) is called, it basically assigns values using the following two functions.

1
2
3
4
5
6
7
8
9
string give_info_t( string question )
{
   string info;

   cout << question << ": ";
   getline (cin,info);
   
   return info;
}

if the answer is text (name, address...), or
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int give_info_n(string question)
{
   int info, bad_input;
    
   do{
   bad_input=0;
   
   cout << question << ": ";
   cin >> info;
   cin.ignore();
   if(!cin)
   {
      bad_input=1;
      cin.clear();
      cin.ignore(numeric_limits<streamsize>::max(),'\n');
      cout << "\nYou made an illegal choice.\n\n";
   }
   }while(bad_input);
   
   return info;
}

if the answer is number (Age, salary)

Example : employee1.m_Name = give_info_t( "Name" );
employee1.m_Age = give_info_n( "Age" );

To read the variables (using different program):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int main()
{
   Employee employee2;

   string filename = "employee_test.txt";
 
   ifstream infile;
   infile.open (filename.c_str(), ios::in|ios::binary);
   
   while( infile.read ( (char *)&employee2, sizeof(Employee) ) )
   infile.close();

   cout << employee2.m_Name << endl;
   ...
   system("pause");
   return 0;
}


I changed the code a bit from my first post, but the problem remains. The values are assigned OK, and I can see that because a display them before I save them in the file, but when I read from the file the first three lines that contain strings are displayed empty and after them all the other numbers are OK.
Last edited on
Don't write write() data structures or classes unless you are sure they are POD types (and even then I wouldn't recommend it, as there are padding and other issues).

strings count as a class. Don't write() them. Ever.

See this thread: http://www.cplusplus.com/forum/beginner/12839/#msg61608


EDIT:

Here's more reading and some code you might find useful:

http://www.cplusplus.com/forum/beginner/30826/#msg167067
Last edited on
As you see it is the simplest type of class. I wanted to test if the save ability of the program was all right, before adding member functions and more information for the employee entity. If I can't make this work, I'll just save to file the information line by line. More troublesome, but at least I've been successful with this.

EDIT: Thanks for the link. I'll give a look right away.
Last edited on
If you want serialization in a class or struct, I would generally make read() and write() members functions that read and write each member from the file, rather than trying to read/write the struct in full.

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
struct Bad
{
  int a;
  int b;
};

struct Good
{
  void Read(istream& s);   // would read() both a and b
  void Write(ostream& s);  // would write() both a and b

  int a;
  int b;
}

//...
Bad bad;
Good good;

file.write( (char*)&bad, sizeof(bad) );  // bad

good.Write(file);  // good 

Would I be able to use the functions to read/write both strings and ints?
I checked http://www.cplusplus.com/reference/iostream/istream/, but it doesn't offer an example.
I find it difficult understanding how to compare two values I get with Read().

Could someone post an example of how to use the functions Read and Write, because istream& and ostream& have me confused

If I use Read to store the name and surname, will it store the full name (with space between them)?

So far I've found example that use istream& operator>> and iterators, but nothing that would help me underastant how to make this work. I'm seriously thinking I should take a IQ test, but I am afraid I won't like the score. Please make it over 100.

EDIT: I just noticed I missed the link in the EDIT: in Disch's post, where he explains some function. I 'll have a look and see what I can make of it.
Last edited on
OK. the examples given by Disch helped a lot, but I would like to know hot to pass to the following function the name of the file I want to save the values in.
S far I was using:
1
2
3
4
ofstream outfile;

filename = "empoyee1.txt";
outfile.open (filename.c_str(), ios::out|ios::binary|ios::app);

to open a file and save the values.

How do I use WriteString when I want to save to employee1.txt the employee.m_Name

1
2
3
4
5
6
7
8
9
10
11
void WriteString(ofstream& file,const string& str)
{
  // get the length of the string data
  unsigned len = str.size();

  // write the size:
  file.write( reinterpret_cast<const char*>( &len ), sizeof(len) );

  // write the actual string data:
  file.write( str.c_str(), len );
}

Last edited on
A few things to note:

The WriteString/ReadString functions I provided are more for reading/writing to a binary file, not a text file.

You're sort of mixing between the two:

1
2
3
4
filename = "empoyee1.txt";  //  .txt implies text file
outfile.open (filename.c_str(), ios::out|ios::binary|ios::app);  // but ios::binary implies binary

// which do you want? 



It sounds to me like you want binary -- not only because you're opening as binary but because you're using read() and write() functions instead of the << and >> operators.

Binary is fine and good (I actually prefer it, myself), but note that it might be confusing if the name the file "*.txt", and you will not be able to view the file in a text editor.

When people see a .txt file they think they can open it in notepad and read it like any normal text file -- but binary data will look like garbage when viewed in notepad. I would recommend you change it to .dat instead of .txt.


As for usage....

1
2
3
4
5
6
7
8
9
ofstream outfile;

filename = "empoyee1.dat";  // changed to .dat to be clear it's binary
outfile.open (filename.c_str(), ios::out|ios::binary|ios::app);


string foo = "Something you want to write to the file";

WriteString( outfile, foo );  // this writes it to the file 
@Disch: Thanks for all the information you provided and the quick response to my plea.
I've managed to write and read from a binary file strings and integers. About the strings, Disch did all the job, as for integers after many hours searching I have the desired result. I post the code of the program I used to test the writing/reading. I found another way to write integers, but included a conversion of the int to char, and I found the one I used simpler. If you have any suggestion about a different way to read/write integers please tell.
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <iostream>
#include <fstream>
#include <string>

using namespace std;


void WriteString(ofstream& file,const string& str)
{
  // get the length of the string data
  unsigned len = str.size();

  // write the size:
  file.write( reinterpret_cast<const char*>( &len ), sizeof(len) );

  // write the actual string data:
  file.write( str.c_str(), len );
}

string ReadString(ifstream& file)
{
  // this probably isn't the optimal way to do it, but whatever
  string str;

  // get the length
  unsigned len;
  file.read( reinterpret_cast<char*>( &len ), sizeof(len) );

  // we can't read to string directly, so instead, create a temporary buffer
  if(len > 0)
  {
    char* buf = new char[len];
    file.read( buf, len );
    str.append( buf, len );
    delete[] buf;
  }
  return str;
}

inline void WriteInteger(ofstream& file, int& num)
{
   file.write(reinterpret_cast<char *>(&num),sizeof(int));
}

int ReadInteger(ifstream& file)
{
   int num;
   file.read(reinterpret_cast<char *>(&num),sizeof(int));
   return num;
}



int main()
{
ofstream outfile;
ifstream infile;


int num1 = 1;
string foo = "First line";
string foo1 = "Another line";

string Name = "Mike";
string filename = Name + ".dat";  // changed to .dat to be clear it's binary
outfile.open (filename.c_str(), ios::out|ios::binary);

WriteString( outfile, foo );  // this writes it to the file
WriteInteger(outfile, num1);
WriteString( outfile, foo1 );
outfile.close();

infile.open(filename.c_str(), ios::in|ios::binary);

string str0 = ReadString(infile);
int num2 = ReadInteger (infile);
string str1 = ReadString(infile);

cout << str0 << endl;
cout << num2 << endl;
cout << str1 << endl;

infile.close();

system("pause");
return 0;
}



Last edited on
Topic archived. No new replies allowed.