Reading/Writing to a binary file

Started by
23 comments, last by Dandi8 13 years, 9 months ago
Hey guys!
I've recently been experimenting with reading and loading binary files. I've written simple tile loading/saving functions which, to my complete and utter amazement, don't work.

The functions are as follows:
void LoadTiles(){	ifstream File("Data/Maps/map.bin", ios::in | ios::binary);	File.read ((char*)&Tiles, sizeof (TileSystem));	File.close();}void SaveTiles(){	ofstream File("Data/Maps/map.bin", ios::out | ios::binary);	File.write ((char*)&Tiles, sizeof (TileSystem));	File.close();}


TileSystem is a class btw. and Tiles is a TileSystem.

Saving results in a 1kb file which may or may not contain my class. Loading *seems* to work but then, apparently, a call to "Tiles.size()" gives me an access violation error.

Gee, programming sure is full of bumpy bumps...
What am I doing wrong?

Thanks in advance :)
Advertisement
Whether or not that is the right code depends on what TileSystem looks like. If TileSystem is non-POD then this probably completely wrong.
Moved to For Beginners.
Here is TileSystem:

struct sTile{	int x, y;	int tileFrame;};class TileSystem{public:	vector<sTile> Tiles;	sSprite Tilesheet;	void InitTiles(int TilesX, int TilesY, string TileSrc, int TilesWidth, int TilesHeight);	void DrawTiles(int camX, int camY, int layer0R, int layer0G, int layer0B);	void FreeMem();};
As SiCrane predicted, you're not outputting Plain Ol' Data. Your TileSystem structure is comprised of a vector<> instance and sSprite (don't know what that is - a pointer to a texture?).

The sizeof(TileSystem) is (guess) 20-30 bytes. That's all you're writing out from the address you pass to Write(..). It's not writing out the contents of the vector (just a pointer structure for an initialized vector<>=just some pointers), and it's writing out some pointer value that you probably got by creating a sprite or something.

When you read it back in, you're not creating a new vector, nor are you creating whatever sSprite is.

To write out the contents of the vector, think more in terms of:

for(size_type i=0; i<Tiles.size(); i++) File << Tiles;

Don't know what sSprite is, but if it's a pointer, you may want to output information that will allow you to create it after you read that info back in.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

As an example, whenever I want to serialize a structure I add two functions that do the heavy work for me:
std::ostream& Engine::Debugger::operator<<(std::ostream& stream, const Callstack& callstack){	stream << callstack.m_stack.size();	for(auto i = callstack.m_stack.begin(); i != callstack.m_stack.end(); ++i)		stream << *i;	return stream;}std::ostrea& Engine::Debugger::operator>>(std::ostrea& stream, Callstack& callstack){	std::size_t n;	stream >> n;	callstack.m_stack.resize(n);	for(std::size_t i = 0; i < n; ++i)	{		int value;		stream >> value;		callstack.m_stack.push_back(value);	}	return stream;}


Of course, this code will only ever compile if the type of the variable "value" defines an operator as well.
sSprite is a struct.

Anyways, I decided to test with this:
void LoadTiles(){	ifstream File("Data/Maps/map.bin", ios::in | ios::binary);	for(int i=0; i<Tiles.Tiles.size(); i++){		File >> (char*)&Tiles.Tiles.tileFrame;	}	File.close();}void SaveTiles(){	ofstream File("Data/Maps/map.bin", ios::out | ios::binary);	for(int i=0; i<Tiles.Tiles.size(); i++){		File << (char*)&Tiles.Tiles.tileFrame;	}	File.close();}



Seems to get me really random results for some reason.
Then I thought, why am I putting a & sign in front of my tiles thingies (I got the method from a tutorial of sorts)? Does that automagically give me a refrence to my variable or is it merely the location of it in the memory which I do not want by any means? Then again, I have no idea how else I'd typecast that into a char.
Please don't beat me with a sledgehammer for my noobtalk.
When I faced the issue of saving/loading things, I did not want to waste too much time on non-game related programming so I opted to use a library for this.

I used (and still do) Boost Serialization to serialize data structures and boost/archive/... to archive the data to/from file.

This, to me, seems a decent, reliable, and easy solution, so I thought I'd mention it.
Thanks but still, I'd like to learn the proper way before thinking of using external libraries for this :)
For your code:
	for(int i=0; i<Tiles.Tiles.size(); i++){		File >> (char*)&Tiles.Tiles.tileFrame;

Did you try just:

File >> Tiles.Tiles.tileFrame;

and do similarly for the File output.

I'm not sure why you're typecasting it. Is there a reason for that? tileFrame is just an int, correct?

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

This topic is closed to new replies.

Advertisement