Saving a binary file help.

G

G-Factor

Hi all

I've just started learning about saving files. I got bit of a problem. The
following code gives me an error about incompatible types. (Cannot covert
from class character to char *). I would appreciate it if anyone could
either help me out, or direct me to an online resource site that has
information on saving/loading classes. I have found several tutorials, but
they either do not really help (saving text files) or are too difficult for
me to understand. Thanks


class character
{
public:
character();
character(string charName);
virtual ~character();

string getCharName();

private:
string name;
int age;
};

void saveFile(character* characterFile)
{

ofstream writeFile;

writeFile.open("game.dat", ios::binary);

writeFile.write((char *)characterFile, sizeof(character));

writeFile.close();

}
 
G

Gianni Mariani

G-Factor said:
Hi all

I've just started learning about saving files. I got bit of a problem. The
following code gives me an error about incompatible types. (Cannot covert
from class character to char *). I would appreciate it if anyone could
either help me out, or direct me to an online resource site that has
information on saving/loading classes. I have found several tutorials, but
they either do not really help (saving text files) or are too difficult for
me to understand. Thanks


class character
{
public:
character();
character(string charName);
virtual ~character();

string getCharName();

private:
string name;
int age;
};

void saveFile(character* characterFile)
{

ofstream writeFile;

writeFile.open("game.dat", ios::binary);

writeFile.write((char *)characterFile, sizeof(character));

DANGER above ... sizeof(character) returns the size of the character
class NOT THE SIZE OF THE STRING.....

I suggest you add a method

operator const & string () const
{
return name;
}

and then you can

writeFile << * characterFile;
 
F

Fabio

Gianni Mariani said:
I suggest you add a method
operator const & string () const
{
return name;
}
and then you can
writeFile << * characterFile;

And what about the 'age' field ?
I guess G-Factor wanted to save both 'age' and 'name' field.

Fabio
 
G

G-Factor

Fabio said:
And what about the 'age' field ?
I guess G-Factor wanted to save both 'age' and 'name' field.

Fabio

Yes, I want to save the entire class.
 
R

Rolf Magnus

Gianni said:
DANGER above ... sizeof(character) returns the size of the character
class NOT THE SIZE OF THE STRING.....

Well, that's only part of the problem. It will of course include the
size of the string object, but that object probably contains a pointer
to the actual string data. With that cast, only the pointer itself
would be written to the file, _not_ the data it points to.
If you don't have a good reason to write the data in binary form, don't.
It's quite unportable (You can't write the structure on a PC and read
it on a MAC, and maybe not even on the same PC using a different
compiler), produces lots of problems (e.g. you can't use classes that
contain pointers or virtual member function - wrt the C++ standard, you
might only have a chance with PODs AFAIK) and in many cases isn't worth
it.
I suggest you add a method

operator const & string () const

You probably meant:

operator const string & () const
{
return name;
}

and then you can

writeFile << * characterFile;

What about the age?
 
F

Fabio

G-Factor said:
Yes, I want to save the entire class.
IMHO you can overload the operator << to save object data into file
(serialize) and >> operator to load object data from file (deserialize)
I wrote a simple example without error-checks so please take it as a pure
sample.

class character
{
public:
character() {};
character(std::string charName) : name(charName) {}
virtual ~character() {};

std::string getCharName();

private:
friend std::eek:stream& operator << (std::eek:stream& s, const character& c);
friend std::istream& operator >> (std::istream& s, character& c);

std::string name;
int age;
};

std::eek:stream& operator << (std::eek:stream& s, const character& c)
{
std::string::size_type stype = c.name.length();
s.write((char*) &stype, sizeof(stype) );
s.write(c.name.c_str(),c.name.length());
s.write((char*) &c.age,sizeof(c.age));
return s;
}

std::istream& operator >> (std::istream& s, character& c)
{
std::string::size_type stype = 0;
s.read((char*) &stype, sizeof(stype) );
char* pstr = new(std::nothrow) char[stype+1];
s.read(pstr,stype);
pstr[stype] = '\0';
c.name = pstr;
delete [] pstr;

s.read((char*) &c.age,sizeof(c.age));
return s;
}

int main()
{
std::eek:fstream ofile("game.dat", std::ios_base::eek:ut | std::ios_base::trunc
| std::ios::binary);

character c1("pippo");

ofile << c1;
ofile.close();

std::ifstream ifile("game.dat", std::ios_base::in | std::ios::binary);

character c2;

ifile >> c2;
ifile.close();

return 0;
}

I hope this simple code can help you.
Fabio
 
F

Fabio

Thomas Matthews said:
3. The binary format of the fields _may_ not be portable across
platforms or compiler implementations.

So why, in your sample, don't you use any signature to identify memory model
(little-endian or big-endian) while saving the integer field ?
4. DO NOT USE OPERATOR<<. The operator is for formatted data,
not unformatted binary data.

Thanks. I forgot that important point.

Fabio
 
T

Thomas Matthews

Fabio said:
So why, in your sample, don't you use any signature to identify memory model
(little-endian or big-endian) while saving the integer field ?

Imagine the size of adding an additional byte for every multibyte
value (not including text).

One could save the Endianess at the beginning of the file.
That would be one flag instead of many.

If you need to deal with Endianism, you could read the value
into a buffer then pass the buffer through an endianism filter.
The filter would swap bytes if necessary. The filter could
be activated based on the header information.

Endianess is no problem if and only if the file stays on
the same platform.

If the file is to be used across platforms, try using
ASCII formatted numbers. Most systems can convert an ASCII
number into native format. The C++ language even has
facilities for this.

Otherwise one has to flag the platform specifics such as
endianess, bits per value and floating point format.

Also, my sample was not complete, but enough to give
you an idea and basis to build upon. I didn't supply
code for buffer support and inheritance.
Thanks. I forgot that important point.

Fabio
--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.raos.demon.uk/acllc-c++/faq.html
Other sites:
http://www.josuttis.com -- C++ STL Library book
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,902
Latest member
Elena68X5

Latest Threads

Top