Hi all. i am writing a simple log in program and i would like to have a class for users that stores the user name and the password as strings. after i have a user created i would like to output the class with the ios::binary flag set and store them in a file user.dat. in know i can the following code to store the class.

User temp("nathan", "password");
ofstream fout("user.dat", ios::binary);
fout.write((char*) &temp, sizeof(temp));
fout.close();

my main concern though is how would i get it back. I'm not sure what i should use for the sizeof() operator when i read from the file.

User temp;
ifstream fin("user.dat", ios::binary);
fin.read((char*) &temp, sizeof( ? ));
fin.close();

any help would be greatly appreciated.

Recommended Answers

All 5 Replies

> fout.write((char*) &temp, sizeof(temp));
This only works for POD data which doesn't contain any pointers.

Any class, or anything which contains pointers (even if you can't see them - so this rules out possibly all the STL types) cannot be simply saved in one step just by writing out a few bytes.

http://www.parashift.com/c++-faq-lite/serialization.html

I remember me facing the same problem a year ago.
I used the following hack rather than calling on boosts serialization :
Lets say we have a string sring_to_be_written which I want to serialize:
1. I first write down the s.size() using fstream::write():

size_t size=string_to_be_written.capacity()+1;
    ofile.write(reinterpret_cast<char *>(&size),sizeof(size));

2.Next I write down the s.c_str() itself:

ofile.write(string_to_be_written.c_str(),size);

To unserialize, I correspondingly read the length of the upcoming string first:

size_t len=0;
    ifile.read(reinterpret_cast<char *>(&len), sizeof(len));

Then I make a cstring with help of new:

char *temp=new char [len];

Then I simply read the string into the cstring and assign it to a std::string.

I am posting those two function from my project as-is. You would definitely have to apt it according to you:

size_t writestring(string string_to_be_written,ofstream & ofile)
{
//This function will read the std::string passed as first parameter and will write it
//to the stream object supplied as second parameter. Returns number of bytes
//written
//Read Developer's Manual section 5.1.3
    size_t size=string_to_be_written.capacity()+1;
    ofile.write(reinterpret_cast<char *>(&size),sizeof(size));
    ofile.write(string_to_be_written.c_str(),size);
    return size+sizeof(size);//return bytes written
}
size_t readstring(string &string_to_be_read,ifstream & ifile)
{
//This function will read std::string from the stream object passed as second 
//parameter into the string reference of the first parameter. Returns number of
//bytes read.
//Read Developer's Manual section 5.1.4
    size_t len=0;
    ifile.read(reinterpret_cast<char *>(&len), sizeof(len));    
    char *temp=new char [len]; // allocate temp buffer for string_to_be_read
    ifile.read(temp, len); // copy name to temp, including '\0'
    string_to_be_read=temp; // copy temp to data member
    delete[] temp;
    return sizeof(len)+len; //return bytes read
}

siddhant3s just to be clear what you are doing is outputting the size of the string in binary and then outputting the string. this way you read the size and then are able to pass that into the sizeof() operator for grabbing the string so you ensure that you have the full string. this makes perfect sense but i wasn't sure if it could be done this way. thank you very much

well i modified the code hat you had posted and I'm running into a little problem. since i am outputting two strings into the file i am writing the size of the name and then the name and then the size of the password and he password but when i run the code it pulls the name twice. I'm guessing that read does not move the input string to the end of where i pulled from and i need to move it forward somehow but I'm not sure how to do that. my code is as follows

// for writing the data
size_t WriteUser(User &user, ofstream &fout)
{
	size_t uName = user.GetName().capacity() + 1;
	size_t uPass = user.GetPassword().capacity() + 1;
	fout.write(reinterpret_cast<char*>(&uName), sizeof(uName));
	fout.write(user.GetName().c_str(), uName);
	fout.write(reinterpret_cast<char *>(&uPass), sizeof(uPass));
	fout.write(user.GetName().c_str(), uPass);
	return (uName + uPass);
}
// and for reading the data
size_t ReadUser(User &user, ifstream &fin)
{
	size_t uName = 0;
	size_t uPass = 0;
	string filename, filepass;
	fin.read(reinterpret_cast<char *>(&uName), sizeof(uName));
	char * name = new char[uName];
	fin.read(name, uName);
	fin.read(reinterpret_cast<char *>(&uPass), sizeof(uPass));
	char * pass = new char[uPass];
	fin.read(pass, uPass);
	filename = name;
	filepass = pass;
	user.SetName(filename);
	user.SetPassword(filepass);
	delete [] name;
	delete [] pass;
	return (uName + uPass);
}

never mind i had a typo on line 9 and was ouputting the name twice. got it figured out thanks much guys.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.