How to write/read class to a binary file properly???

Started by
8 comments, last by Zahlman 17 years, 8 months ago
Main Code

#include <iostream>
#include <iomanip>
#include <string>
#include <cstdlib>
#include <fstream>
#include <vector>
#include "shortphone.cpp"
#include "shortname.cpp"
#include "shortaddress.cpp"
using namespace std;

class Record{
shortName    Name;
shortAddress Address;
shortPhone   Phone;
public:
	void AddNewRecord();
	void ViewRecord();
	int FindRecord();

};


int menu()
{
	int choice;
	cout <<"     Record List Processing System    "<<endl;
	cout <<"1.   Add New Record "<<endl;
	cout <<"2.   Remove A Record Object from the list"<<endl;
	cout <<"3.   View all record object"<<endl;
	cout <<"4.   Find the object"<<endl;
	cout <<"5.   Exit"<<endl;
	
	cin >> choice;
	return choice;
}



/*void Record::InFile(ofstream fout)
{
	
	string output = Name.getFirst();
	fout.write((char*) &output, sizeof(Name.getSizeFirst()));
	fout.write(output.c_str(), Name.getSizeFirst());
	output = Name.getLast();
	fout.write((char*) &output, sizeof(Name.getSizeLast()));
	fout.write(output.c_str(), Name.getSizeLast());

	

}*/

void Record::AddNewRecord() 
{ 
	cin.ignore();
	
	string input;

	cout << "First Name :";
    getline(cin,input,'\n');
	Name.setFirst(input);

	cout << "Last Name  :";
    getline(cin,input,'\n');
	Name.setLast(input);

	cout << "ID:      :"; //Address
    getline(cin,input,'\n');
	Address.setID(input);

	cout << "Street   :";
	getline(cin,input,'\n');
	Address.setStreet(input);

	cout << "City     :";
	getline(cin,input,'\n');
	Address.setCity(input);

	cout << "State    :";
	getline(cin,input,'\n');
	Address.setState(input);

	cout << "Zip    :";
	getline(cin,input,'\n');
	Address.setZip(input);
	
	cout << "Area Code      :";
	getline(cin,input,'\n');
	Phone.setArea(input);

	cout << "Telephone - Prefix :";
    getline(cin,input,'\n');
	Phone.setPrefix(input);

	cout << "Telephone - Numbers:";
    getline(cin,input,'\n');
	Phone.setNumber(input);
	
	input.erase();
}


void Record::ViewRecord()
{
	cout << Name.getFirst() <<" " << Name.getLast() <<" ";
	cout << Address.getID() <<" " << Address.getCity() <<" " << Address.getStreet() <<" " << Address.getState() <<" " << Address.getZip() <<setw(4) ;
	cout << Phone.getArea() <<" " <<Phone.getPrefix() <<"-" << Phone.getNumber() <<endl;
}

int Record::FindRecord()
{
	cin.ignore();

	string input,last_name;
	int i = 1;
	last_name = Name.getLast();

	cout <<"Enter the last name :";
	getline(cin, input);

	i=last_name.compare(input);
	return i;
}

typedef vector<Record>    SetRecord;

int main()
{
	SetRecord GrowingRecord;
	ofstream fout("info.dat", ios::binary|ios::app);
	ifstream fin("info.dat", ios::binary);
	
	for(;;){
		int choice = menu();
		switch(choice)
		{
		case(1):
			{
				Record Employee;
				Employee.AddNewRecord();
				GrowingRecord.push_back (Employee);
//				Employee.InFile(fout);
				break;
			}
		case(2):
			{
				int i,j;

				cout <<"Index " << " Name " << setw(2) << " ID " << setw(2) << " Street " << setw(5) << " City "  << setw(5) <<"State "<<setw(2) << " Telephone " <<endl;
				for(i=0; i<GrowingRecord.size();i++)
				{
					Record Employee;
					Employee = GrowingRecord;
					cout << i << setw(2);
					Employee.ViewRecord();

				}
				if(i==0){
					cout <<"No Records Exist! "<<endl;
					break;
				}
				cout << "Which record do you wish to delete (-1 to exit) ? (0-" << i-1 <<")" ;
				cin >> j;

				GrowingRecord.erase(GrowingRecord.begin()+j);
			}
			break;
				
		case(3):
			{
				
				cout <<"Index " << " Name " << setw(2) << " ID " << setw(2) << " Street " << setw(5) << " City "  << setw(5) <<"State "<<setw(2) << " Telephone " <<endl;
				for(int i=0; i<GrowingRecord.size();i++)
				{
					Record Employee;
					Employee = GrowingRecord;
					cout << i << " ";
					Employee.ViewRecord();

				}
			break;
			}
		case(4):
			{	
				int j;
				for(int i=0; i<GrowingRecord.size();i++)
				{
					Record Employee;
					Employee = GrowingRecord;
					if((j=Employee.FindRecord()==0)){
						cout <<"Found !"<< "The data is located at " << i << "th data" <<endl; break;}
					else
						cout <<"Not Found !";
				}
			break;

			}
		case(5):
			 exit(1); break;
	
		default:
			cout <<"Error" << endl;
		};
	}
	return 0;
}

ShortPhone Definition

#include <iostream>
using namespace std;

const string null = "";  //Define a constant null value...

class shortPhone  {
  string AreaCode;
  string Prefix;
  string Number;
 
public:
  //Declare the constructors...
  
  shortPhone();
  shortPhone(string, string, string);
  
  //Define the mutators...
  
  void setArea(string Area)    { AreaCode = Area; }
  void setPrefix(string Pref)  { Prefix = Pref; }
  void setNumber(string Num)   { Number = Num; }
  
  //...and the accesors...
  
  string getArea()             { return AreaCode; }
  string getPrefix()           { return Prefix; }
  string getNumber()           { return Number;   }
};

//Define the default constructor...

shortPhone::shortPhone()
{
   AreaCode  = null;
   Prefix    = null;
   Number    = null;
}
  
 
//Define the initializing one...

shortPhone::shortPhone(string Area, string Pre, string Num)
{
   AreaCode  = Area;
   Prefix    = Pre;
   Number    = Num;
}
  



ShortName Definiton

#include <iostream>
#include <string>
#include <vector>
using namespace std;


//const string null;  //Define a constant null value...



class shortName  {
   string firstName;  
   string lastName;

public:  
  //Declare the constructors...
  
  shortName();
  shortName(string, string);  
   
   //Define the mutator member functions...
   
   void setFirst(string First)  { firstName = First;}
   void setLast(string Last)    { lastName  = Last;}
   
   //...and some accessor functions
   
   string getFirst()            { return firstName;}
   string getLast()             { return lastName;}
   int getSizeFirst()        { return sizeof(firstName);}
   int getSizeLast()			{ return sizeof(lastName);}
   
};

//Define the default constructor...

shortName::shortName()
{
  firstName = "New First Name";
  lastName  = "New Last Name";
}

 //...and the initializing one...
 
shortName::shortName(string First, string Last)
{
  firstName = First;
  lastName  = Last;
}



ShortAddress Definition

#include <iostream>
#include <string>
#include <vector>
using namespace std;

//const string =0;  //Define a constant null value...

class shortAddress  {
  string StreetID;
  string StreetName;
  string CityName;
  string StateName;
  string ZipCode;
 
public:
  //Declare the constructors...
  
  shortAddress();
  shortAddress(string, string, string, string, string);
  
  //Define the mutators...
  
  void setID(string ID)         { StreetID = ID;      }
  void setStreet(string Street) {StreetName = Street; }
  void setCity(string City)     { CityName = City;    }
  void setState(string State)   { StateName = State;  }
  void setZip(string Zip)       { ZipCode = Zip;      }
  
  //...and the accesors...
  
  string getID()                { return StreetID; }
  string getStreet()            { return StreetName; }
  string getCity()              { return CityName;   }
  string getState()             { return StateName;  }
  string getZip()               { return ZipCode;    }
};

//Define the default constructor...

shortAddress::shortAddress()
{
   StreetID   = "New";
   StreetName = "New";
   CityName  = "New";
   StateName ="New";
   ZipCode   = "New";
}
  
 
//Define the initializing constructor...

shortAddress::shortAddress(string ID, string Street, string City, string State, string Zip)
{
   StreetID   = ID;
   StreetName = Street;
   CityName  = City;
   StateName = State;
   ZipCode   = Zip;
}



ShortPhone Definition


#include <iostream>
using namespace std;

const string null = "";  //Define a constant null value...

class shortPhone  {
  string AreaCode;
  string Prefix;
  string Number;
 
public:
  //Declare the constructors...
  
  shortPhone();
  shortPhone(string, string, string);
  
  //Define the mutators...
  
  void setArea(string Area)    { AreaCode = Area; }
  void setPrefix(string Pref)  { Prefix = Pref; }
  void setNumber(string Num)   { Number = Num; }
  
  //...and the accesors...
  
  string getArea()             { return AreaCode; }
  string getPrefix()           { return Prefix; }
  string getNumber()           { return Number;   }
};

//Define the default constructor...

shortPhone::shortPhone()
{
   AreaCode  = null;
   Prefix    = null;
   Number    = null;
}
  
 
//Define the initializing one...

shortPhone::shortPhone(string Area, string Pre, string Num)
{
   AreaCode  = Area;
   Prefix    = Pre;
   Number    = Num;
}
  



I tried to export it to a binary file, but i'm not able to read it back. the biggest problem i've found is that the class contains other classes which makes it difficult to be written out to a file. What can I need to do to make the program reading the binary file correctly? excuse my poor english
Advertisement
libs11n might be useful to you: http://s11n.net/
It does exactly what you're asking.
huh....this looks good...but way too complex to me...

is it possible to write out the vector in a easier way?
Not really. Look up "serialization" on Google. You need to save each member of the class seperately, since pointers are meaningless between runs of the program.
Serialization.
boost::serialization may also be deeper than you intended to travel, but it does work very well.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

thx all help from you people~ 'Orz

I finally got the serializing code written
[code source="cpp"
....
void Record::InFile()
{

Read_Str(Name.getFirst());
Read_Str(Name.getLast());

Read_Str(Address.getCity());
Read_Str(Address.getID());
Read_Str(Address.getState());
Read_Str(Address.getStreet());
Read_Str(Address.getZip());

Read_Str(Phone.getArea());
Read_Str(Phone.getNumber());
Read_Str(Phone.getPrefix());



}
void Read_Str(string str)
{
ofstream fout("info.dat", ios::binary|ios::app);
string data;
data = str;
int tmp = data.size();
fout.write(reinterpret_cast(&data), sizeof(tmp) );
fout.write(data.c_str(), tmp+1);
fout.close();
}


I checked info.dat, i found all data entered is shown in the file

However I got stuck when trying to deserialize the code

<br><br>string Write_Str()<br>{<br> ifstream fin("info.dat",ios::binary);<br> string data;<br> int len=0;<br> char *p=0;<br><br> fin.read(reinterpret_cast(&len), sizeof(len) );<br> p=new char [len+1];<br> fin.read(p, len+1);<br> data = p;<br> cout<br> <br>
thanks for the replies....

I finally got the serializing code written
....void Record::InFile(){Read_Str(Name.getFirst());Read_Str(Name.getLast());Read_Str(Address.getCity());Read_Str(Address.getID());Read_Str(Address.getState());Read_Str(Address.getStreet());Read_Str(Address.getZip());Read_Str(Phone.getArea());Read_Str(Phone.getNumber());Read_Str(Phone.getPrefix());}void Read_Str(string str){ofstream fout("info.dat", ios::binary|ios::app);string data;data = str;int tmp = data.size();fout.write(reinterpret_cast(&data), sizeof(tmp) );fout.write(data.c_str(), tmp+1);fout.close();}


I checked info.dat, i found all data entered is shown in the file

However I got stuck when trying to deserialize the code

[source lang = "cpp"]string Write_Str(){ifstream fin("info.dat",ios::binary);string data;int len=0;char *p=0;fin.read(reinterpret_cast(&len), sizeof(len) );p=new char [len+1];fin.read(p, len+1);data = p;cout<< data;fin.close();return data;}


the first character of the file is shown...but the rest are the junk :/
plz help >.<
can anyone offer me suggestions ?? many thanks
void Read_Str(string str){ofstream fout("info.dat", ios::binary|ios::app);string data;data = str;int tmp = data.size();fout.write(reinterpret_cast(&data), sizeof(tmp) );fout.write(data.c_str(), tmp+1);fout.close();}


That code:

0) Seems to have a syntax error: What are you reinterpret_casting *to*?

1) Is incorrectly named: this is the writing function, and the other one is the reading function.

2) Tries to use the first few bytes of the std::string object in memory for the length count, instead of the 'tmp' value - this is the real bug.

3) Writes the null terminator of the string, which is not a big problem, but should be accounted for in the reading code.

4) Needlessly closes the file (it will be closed automatically by the object's destructor) and needlessly copies the string object in memory - twice.

5) Will reopen and reclose the file for every string that is written, which is very inefficient (although for the data you showed it is unlikely to matter).

I usually write a helper function for serializing "primitives" to an existing stream first (to avoid the mistake that occurs here with writing the length count), and then make a variant for strings:

template <typename T>ostream& serialize_binary(ostream& os, const T& obj) {  os.write(reinterpret_cast<char*>(&obj), sizeof(T));  return os;}ostream& serialize_binary(ostream& os, const std::string& str) {  std::string::size_type size = str.length();  serialize_binary(os, size);  os.write(str.data(), size);  return os;}// Add more specializations for other complex types


Then open an ostream in a different function, and make repeated serialize_binary calls with that ostream.

Reading is similar, except that you can't read directly to the string object (because it might not provide a solid chunk of memory):

template <typename T>istream& deserialize_binary(istream& is, T& obj) {  is.read(reinterpret_cast<char*>(&obj), sizeof(T));  return is;}istream& deserialize_binary(istream& is, std::string& str) {  std::string::size_type size;  deserialize_binary(is, size);  vector<char> buffer(size);  os.read(&(buffer[0]), size);  str.assign(buffer.begin(), buffer.end());  return os;}// Add more specializations for other complex types


This topic is closed to new replies.

Advertisement