Skip to main content
GameDev.net gamedev.net
🔒 Locked

Files Streams in Binary mode

Started by Lorek Mar 14, 2005 at 9:51 PM 3 replies 1.9k views
Original Post
Lorek
Lorek
I've been working teaching myself C++ for awhile now, I'm working on file streams in binary mode right now. My read and write functions are below. I'm going to be writing and reading custom objects. What i'm having trouble with is finding the best, most dynamic way to write these and return the information retrieved back to my main function. The ways I know how to do this are, in main() obj temp = read(); or setting a point to hold the memory address of the variable returned. I'm pretty sure theres an easier, simpler way to do this but I'm at a loss right now. I'd prefer not to use a global variable. obj read(int num) { obj temp; ifstream infile; infile.open("DATA.DAT", ios::binary); infile.seekg( num*sizeof(Int) ); infile.read( reinterpret_cast(&temp), sizeof(temp) ); return temp; } void write(obj temp) { ofstream outfile("DATA.DAT", ios::binary); outfile.write(reinterpret_cast(&temp), sizeof(temp) ); }
Zahlman
Zahlman
Don't open the file for each read/write call. Also, don't try to calculate magic file locations and then seek to them. Instead, just read/write one item at a time, having a little wrapper method to handle it.

One option for POD types and primitives would be something like:
// Create new itemtemplate <typename T>T read(istream &is) {  T result;  is.read(reinterpret_cast<char*>(&result), sizeof(result));  return result;}// Initialize existing itemtemplate <typename T>void read(istream &is, T ␣) {  is.read(reinterpret_cast<char*>(␣), sizeof(blank));}// Output itemtemplate <typename T>void write(ostream &os, T &item) {  os.write(reinterpret_cast<char*>(&item), sizeof(item));}


Which is very much like what you already have. However, you should not try to handle anything that's at all complex this way (i.e. if the object contains pointers, has non-trivial ctor/dtor, or in any way cares about its or anything else's location in memory), you should make the class hold the information about how to do the serialization:

// The classes provide methods:// - ctor taking an istream&// - either friend istream::operator>>, or a copy ctor and assignment operator// - friend ostream::operator<<// Create new itemtemplate <typename T>T read(istream &is) {  return T(is);}// Initialize existing itemtemplate <typename T>void read(istream &is, T ␣) {  blank = T(is); // using assignment operator  // or: is >> blank; using an istream operator>> definition}// Output itemtemplate <typename T>void write(ostream &os, T &item) {  os << item;}


If you want to use both, you'll need to do some kind of template magic in order to differentiate POD types from non-POD types. (Or you could just let all your non-trivial classes derive from some 'Serializable' ABC, and specialize the template for that.)

Also, if you want to have both 'text' and 'binary' representations for your objects, and choose one to serialize as/deserialize from at runtime, then obviously you can't really do the job with just << and >>. [smile]

But what do I know? You should read what someone really knowledgable has to say about this serialization stuff.
Lorek
Lorek
serialization? i'm not familiar with that term.
SirLuthor
SirLuthor
If I recall correctly, serialization is simply the act of turning the data of an object into a stream of bytes that can be written directly to a file (or sent across a network as packets), and re-interpereted into the data when it is read back out again with a corresponding 'un-serialize' method. I'm afraid that was ghastly and most unclear, but, well, methinks you will have to wait until a more knowledgeable person then I comes along to get a better explanation [smile]
Cheers!
Free speech for the living, dead men tell no tales,Your laughing finger will never point again...Omerta!Sing for me now!
thec
thec
Quote:
Original post by SirLuthor
If I recall correctly, serialization is simply the act of turning the data of an object into a stream of bytes that can be written directly to a file (or sent across a network as packets), and re-interpereted into the data when it is read back out again with a corresponding 'un-serialize' method. I'm afraid that was ghastly and most unclear, but, well, methinks you will have to wait until a more knowledgeable person then I comes along to get a better explanation [smile]
Cheers!


Yeah, you're right. It's not that important how you save the data, just you can bring it back up to the data structures again.

A good thing could be to implement a class "Serialize" or similar, java does this, with only two methods, in c++ "const std::string serialize()=0;" and "void deserialize(const std::string& input)=0;" and just inherit that interface into whatever class you need serializeable.

This makes sure the class which needs to be serialized/deserialized gets the proper interface, which then the program can rely on when using it.

That way, you can store a list of Serialize object pointers to make sure you load/save all of them at once for instance, just from the top of my head.

And a pretty interface is always a good thing :)

Good luck
Albert "thec" Sandberg

Ps. The =0 thing in the interface class means you _have_ to include those methods in the class which inherits Serialize... Ds.
-------------------------------------------http://www.thec.org

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.