CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 7 of 7
  1. #1
    Join Date
    Aug 2006
    Posts
    3

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

    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();
    	void InFile();
    	void OutFile();
    	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 Read_Str(string str)
    {
    	ofstream fout("info.dat", ios::binary|ios::app);
    	string data;
    	data = str;
    	int tmp = data.size();
    	fout.write(reinterpret_cast<char *>(&tmp),sizeof(int));
    	fout.write(reinterpret_cast<char *>(&data), sizeof(tmp) );
    	fout.write(data.c_str(), tmp+1);
    	fout.close();
    }
    
    
    
    
    
    
    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 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;
    	
    	for(;;){
    		int choice = menu();
    		switch(choice)
    		{
    		case(1):
    			{
    				Record Employee;
    				Employee.AddNewRecord();
    
    				Employee.InFile();
    				GrowingRecord.push_back (Employee);
    				
    				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[i];
    					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[i];
    					cout << i << " ";
    					Employee.ViewRecord();
    
    				}
    			Record Employee;
    			
    			break;
    			}
    		case(4):
    			{	
    				int j;
    				for(int i=0; i<GrowingRecord.size();i++)
    				{
    					Record Employee;
    					Employee = GrowingRecord[i];
    					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;
    }
    here is the code...i got no problems when reading out the classes into a binary file....but it prints junk or nth when i read it back

    can anyone figure out the problem??? many thanks

  2. #2
    Join Date
    Aug 2005
    Posts
    478

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

    Code:
    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<char *>(&tmp),sizeof(int));
    	fout.write(reinterpret_cast<char *>(&data), sizeof(tmp) );
    	fout.write(data.c_str(), tmp+1);
    	fout.close();
    }
    That code, especially

    Code:
    fout.write(reinterpret_cast<char *>(&data), sizeof(tmp) );
    Is extremely wierd. First of all, you will not get good results writing an object that is not a POD (Plain Old Data) type in binary, as you do with that std::string. Secondly, you write only sizeof(tmp) bytes of the std::string to the file, only 4 bytes on a 32 bit machine.

    Also funky about your code, is that you include other source files. This should not be necessary. You can have declarations of your classes and methods in header files, and include those in the source files that you need to, and then have other source files implement those methods. Generally good article: http://www.gamedev.net/reference/pro...ures/orgfiles/

  3. #3
    Join Date
    Aug 2006
    Posts
    3

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

    Quote Originally Posted by Calculator
    Code:
    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<char *>(&tmp),sizeof(int));
    	fout.write(reinterpret_cast<char *>(&data), sizeof(tmp) );
    	fout.write(data.c_str(), tmp+1);
    	fout.close();
    }
    That code, especially

    Code:
    fout.write(reinterpret_cast<char *>(&data), sizeof(tmp) );
    Is extremely wierd. First of all, you will not get good results writing an object that is not a POD (Plain Old Data) type in binary, as you do with that std::string. Secondly, you write only sizeof(tmp) bytes of the std::string to the file, only 4 bytes on a 32 bit machine.

    Also funky about your code, is that you include other source files. This should not be necessary. You can have declarations of your classes and methods in header files, and include those in the source files that you need to, and then have other source files implement those methods. Generally good article: http://www.gamedev.net/reference/pro...ures/orgfiles/
    thx for your reply...
    actually these 3 extra headers are already written by my teacher....

    can you tell me how to write the code correctly?

  4. #4
    Join Date
    Aug 2005
    Posts
    478

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

    Well, as you have it, InFile outputs data because it uses Read_Str, which seems to write data. Little wierd, but okay? If your teacher told you to include those source files, you may show that article to him (if he/she is cool or something). I can only guess that OutFile, which reads in things () is in one of those other source files, and I can't see how it is being read. But what you could do, is have length-prepended strings in your data file, or null-terminated strings (which do not know their own length) in the file. With length prepended, it would be like:

    Code:
    void Read_Str(string str)
    {
    	ofstream fout("info.dat", ios::binary|ios::app);
    	int tmp = str.length();
    
    	fout.write(reinterpret_cast<char *>(&tmp),sizeof(tmp));
    	fout.write(data.c_str(), tmp);
    
    	// You wrote a length prepended string to the file.
    	// i.e. "Hello!" in the file would look like
    	// <binary data representing 6>Hello!
     
    	fout.close();
    }
    With null-terminated, it would be like:

    Code:
    void Read_Str(string str)
    {
    	ofstream fout("info.dat", ios::binary|ios::app);
    
    	fout.write(data.c_str(), tmp + 1);
    
    	// You wrote a null-terminated c string
    	// i.e. "Hello!" in the file would look like
    	// Hello!\0
     
    	fout.close();
    }
    To read the strings from the file, you would for length prepended:

    Code:
    	int length = 0;
    	inFile.read(reinterpret_cast<char*>(&length), sizeof length);
    	inFile.read(buffer, length);
    
    	string someString(buffer);
    
    	// Now some string is an std::string recreated from
    	// A length prepended string
    Or for null terminated

    Code:
    	string someString;
    	char tmp;
    	while((tmp = inFile.get()) != 0)
    	{
    		someString += tmp;
    	}
    
    	// Now someString was re-created from a
    	// null-terminated c string in the file
    Or something.

  5. #5
    Join Date
    Aug 2006
    Posts
    3

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

    nice.....eventually i got the first list of data entered
    however, it encountered other problems when i push it into a vector.

    i copied the code to the main(), and i ran the following code

    Record Employee;

    for(int i=1;i<10;i++)
    {

    while(outFile.good())
    {


    int length =0;
    outFile.read(reinterpret_cast<char*>(&length), sizeof length);
    outFile.read(buffer, length);
    string SomeBuffer(buffer);
    cout << buffer << endl;

    Employee.OutFile(SomeBuffer,i);

    }
    }

    it displays junk after a complete string.....why??

  6. #6
    Join Date
    Apr 2006
    Location
    Nr Cambridge, UK
    Posts
    263

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

    Quote Originally Posted by lost_scott
    outFile.read(buffer, length);
    string SomeBuffer(buffer);
    cout << buffer << endl;
    it displays junk after a complete string.....why??
    You are constructing your string from a buffer that isn't null-terminated, yet you don't provide the length. You want:
    Code:
    string SomeBuffer(buffer, length);

  7. #7
    Join Date
    Oct 2000
    Location
    London, England
    Posts
    4,773

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

    There is no method to obtain a writable buffer to a string to write into, so to read back from the file you have to use vector<char> which does give you a writable buffer (of a variable size) and then copy the buffer.

    Unfortunately this is also one of the inefficiencies of the standard library. firstly you create a vector of char which it has to initialise even though you don't need it initialised. Then after reading the contents in from a file (via yet another buffer that is used for the streambuf) you have to copy it into your string - string doesn't have a swap method with vector<char> - it can't because string isn't guaranteed to have a contiguous buffer.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured