Advertisement

File IO in C++

Started by March 15, 2002 03:17 PM
20 comments, last by yottskry 22 years, 9 months ago
Hey all, Is it possible to create a file of structs in C++ as you would create a file of records in Pascal? Eg, in pascal you''d have type man = record integer : height; integer : age; end; var manfile : file of man; Is there any C++ equivalent because everything I''ve found online is about just reading and writing strings. Thanks, Steve
"All the girls that turn me on (turn me down)"
Of course it''s possible, but you may have to do quite a lot of the groundwork yourself. If you are using some platform-specific API, then you could look into using the serialisation mechanisms provided with that. If you wish to create your own mechanism, then there are a few things you must consider. For example, do you want the mechanism to be platform-independent? Will you be serialising a class which contains pointer data? On deserialisation, do you want to create different types according to the retrieved data? I won''t go into these as they can get quite complicated, and you might not care.

As a basic mechanism, you can basically create streaming operations for your class, to allow you to dump the class representation, or create a class from a file containing a class representation. Here''s an (admittedly rather silly) example:


  #include <iostream>class Thing{public:	Thing() : val_(0) {}	explicit Thing( int val ) : val_(val) {}	explicit Thing( std::istream& is )	{		is >> val_;	// warning: this can fail!	}	int	getVal() const { return val_;}private:	int val_;};std::ostream& operator<<( std::ostream& os, const Thing& t ){	return os << t.getVal();}int main(){	Thing t1(5);	std::cout << t1 << std::endl;	Thing t2(std::cin);}  


The key points here are that you can dump an instance of Thing to file using the << operator, and you can construct a class from the contents of an input stream, by passing the input stream to Thing''s istream conversion constructor. In this case, you''d need to consider what happens if the input stream contains the wrong sort of data - you''d need some way of determining the object is unusable, and a means of recovering from that situation.

Note that you might not want to use the << operator, since you might use that do display a formatted representation of the class. In which case, you might have a "Serialise()" member function aswell.

Hopefully this gives you an idea of the basic mechanisms, and some of the issues that you might face.

--
#exclude
Advertisement
Hmmmm, I''m not sure I even understand that.

Let me try a different approach...has how would anyone here store the positions of bricks for each level of a breakout clone?

I made a DOS version using pascal about 6 months ago and stored each level''s brick positions and colours in a seperate file (one file per level)...now I''m remaking my game using SDL to help me learn both SDL and C++ and would like to know if any one has any suggestions.

Thanks

Steve
"All the girls that turn me on (turn me down)"
Your "record" format:
brick_x:brick_y:brick_color

Read from/write to file in a loop. Live long.

[ GDNet Start Here | GDNet Search Tool | GDNet FAQ | MS RTFM [MSDN] | SGI STL Docs | Google! ]
Thanks to Kylotan for the idea!
You can output a struct to a binary file all at once using C++. Just use type coercion. It'll only work on Intel/AMD/compatible CPUs, but I doubt anyone without one is in your intended audience.


    mystruct data;myFile.write((char*)(&data), sizeof(mystruct));    


[edited by - TerranFury on March 15, 2002 6:52:48 PM]
for object's data I use:


        Typdef struc {   int Pos[200];   int BrickShape[200];   BOOL SpecialBehaviour[200];   char LevelName[255];   int  LevelNumber;   // whatewer you want Excepted variable size value like CString}BRICK;//declare the variable of structure type BRICKBRICK MyBrick;  


you acces your data by:

MyBrick.Pos[BrickNbr]=0;
Notice that you can now use your structure for several data
when declaring it:
BRICK BlueBrick;
BRICK NoBrick;

at use time:
BlueBrick.Pos[]
NoBrick.Pos[]


Write all your structure in one burst using :


  SaveBrickData(char LevelFilename){    FILE * Stream;    //Open the file    Stream= fopen( LevelFilename, "wb");    if(Stream==NULL)    {       //error disk full ?    }    else    {      //write the data      fwrite(&MyBrick, Sizeof(MyBrick), 1, Stream)      fclose( Stream)    }}  and load with:      LoadBrickData(char LevelFilename){    FILE * Stream;    //Open the file    Stream= fopen( LevelFilename, "rb");    if(Stream==NULL)    {       //file not found    }    else    {      //fill my structure back with all value saved      fread(&MyBrick, Sizeof(MyBrick), 1, Stream)      fclose( Stream)    }}  


I use this for object's data, terrain data , screen option file etc etc this work well and fast without headeach.


Hope this help ?

DanSteph


Css's forum, Screenshot


[edited by - Dansteph on March 15, 2002 6:12:19 PM]
Advertisement
TerranFury: That approach is subject to all sorts of problems, since it will write the exact object representation. That means it will include things such as a vtable, pointer members, and whatever other "funnies" exist. It might work, it might not, but it's not really robust or "industrial strength".

--
#exclude &ltwindows.h>

[edited by - SabreMan on March 15, 2002 6:05:49 PM]
quote: Original post by SabreMan
TerranFury: That approach is subject to all sorts of problems, since it will write the exact object representation. That means it will include things such as a vtable, pointer members, and whatever other "funnies" exist. It might work, it might not, but it''s not really robust or "industrial strength".

Yeah, you wouldn''t want to use it with classes. Doing so would constitute a ''bad idea''™.

However...
quote: Original post by yottskry
Is it possible to create a file of structs [emphasis added] in C++...

If you''re using structs containing nothing but member variables, nothing is stopping you from using this method. You just need to make sure you explicitly specify how the struct is padded. This technique also makes certain types of bit-level file IO very easy, using bitfields.

For general classes, though, you really should just bite the bullet and write a member function to save to a file.
quote: Original post by yottskry
Hmmmm, I''m not sure I even understand that.

That''s not a good reason to dismiss the approach. The code I wrote is actually very basic. Unfortunately, most people learn their C++ coding habits from either Windows books or Schildt / Liberty books.

quote:
Let me try a different approach...has how would anyone here store the positions of bricks for each level of a breakout clone?

I would use an approach very similar to what I showed you, although I would combine it with the STL. I''d probably have every brick (or Thing in this case) stored in a collection class representing the map of the screen. When I saved the map, I''d iterate through the collection, serialising each item. For example, let''s suppose I thought std::vector was a good collection to use (I happen to think it probably isn''t, but that''s unimportant at the moment). Then, I might write something like the following:


  typedef std::vector<Thing> thing_collection;int main(){	thing_collection things;	// load "things" from the standard input:	bool loop = true;	while(loop)	{		Thing temp(std::cin);		if(temp.isOK())			things.push_back(temp);		else			loop = false;	};	// this writes all "things" to the standard output:	std::copy( things.begin(), things.end(), 		std::ostream_iterator<Thing>(std::cout, " "));}  


First, I have a loop which loads all the things from an input stream into my things collection. I''ve had to add an isOK() method to check the Thing was constructed correctly, but that''s easy. Then, since my Thing class has an operator<< defined, I can save the things in the collection using a single line of code.

--
#exclude &ltwindows.h>
quote: Original post by TerranFury
If you''re using structs containing nothing but member variables, nothing is stopping you from using this method.

In C++, a struct *is a* class (do I sense Deja Vu here?). The technique is rather brittle, since it makes assumptions about the object representation. It''s also not really C++.

This topic is closed to new replies.

Advertisement