• Advertisement

Archived

This topic is now archived and is closed to further replies.

Classes reading/writing to files

This topic is 5039 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am currently trying to save a class to a binary file
#include <stdio.h>
#include <stdlib.h>

#include <iostream>
#include <fstream>
......

int main()
{
	/*The choice to read or write, 0 writes and 1 reads*/
	short cho = 0;
	std::cin >> cho;

	Init();

	/*Writing block*/
	if( (cho == 0) || (cho == 3) )
	{
			Statspr    gas( "data/pic/gas.bmp" , "data/pic/gas.bmp" , "data/pic/gasc.bmp" );
			gas.x = 300;		gas.y = 200;

			Array array;
			array.Push( gas );

			gas.x = 500;
			array.Push( gas );

 		std::ofstream ofile;
 		ofile.open("shit", std::ios::binary );
 		ofile.write((char *) &array , sizeof array);
 		ofile.close();
	}

	/*Reading block*/
	if( (cho == 1) || (cho == 3) )
	{
			Array sheet;

 		std::ifstream ifile;
 		ifile.open("shit" , std::ios::binary );
 		ifile.read((char*) &sheet , sizeof sheet);
 		ifile.close();

		/*Draw the sprite to the screen*/
 		sheet.Rad(0)->Draw();	SDL_Flip(screen);	SDL_Delay(4000);
	}



	/*What was your choice*/
	pr "\ncho is " << cho << ''\n'';

	SDL_Quit();
	exit(1);
	return 0;
}
 
as such, choosing to write then read (entering 3) will display the picture but saving in one run(0), then in the second run reading(1) will not display anything. I have tried something like
			Array sheet;
			char *adress = &sheet;

 		std::ifstream ifile;
 		ifile.open("shit" , std::ios::binary );


		while(ifile.get(*adress))
		{	adress++;		}
 
but of course there is no way to make a char pointer point to a class... Is there anyway I could write a whole class to a binary file using one app, and read it using a second app? Also how can I reference a pointer of one type to another?

Share this post


Link to post
Share on other sites
Advertisement
Remember that saving a pointer doesn't save what it points to.

but of course there is no way to make a char pointer point to a class...

Yes, there is : (char*) &object

Is there anyway I could write a whole class to a binary file using one app, and read it using a second app?

Yes. Watch out for those pointers in the class though. If it does contain any, you've got to save it one member at a time.

Also how can I reference a pointer of one type to another?

A cast?

[edited by - Fruny on May 8, 2004 7:56:56 AM]

Share this post


Link to post
Share on other sites
A class containing dynamically allocated memory cannot be written to disc directly and be restored correctly later. You can make a char* point to anything, but that is not your solution. You need to overload operators >> and << to properly read and write your class. Then the write code is no more then ''myfstream << myclass'', and the read is, similarily, ''myfstream >> myclass''.

The string literals in your sprite constructor suggest that you are using std::string, which contains dynamic memory. The usage of your Array class also suggest it contains dynamic memory.

Chances are, writing that Array to disc is only writing a pointer. Loop through the elements and write them all seperatly.

Share this post


Link to post
Share on other sites
First of all, I don't think this is a serious issue, but you should use the combination of flags std::ios::binary | std::ios::out for writing a binary file, and the combination of flags std::ios::binary | std::ios::in for reading a binary file. I think it still works with just the std::ios::binary flag, but it's not good practice to do that.

Anyways, you need what's called serialization - turning a class into raw data and back again. You should give your class to public methods called Serialize and Deserialize. For example:
class MyClass
{
public:
void Serialize(std::ostream & out); // Serialize this object to the ostream out

void Deserialize(std::istream & in); // Deserialize from istream in into this object

...
private:
int anInt;
double aDouble;
char aCstring[64];
SomeObject anObject;
SomeObject *aPointer;
};

void MyClass::Serialize(std::ostream & out)
{
out.write((char *)&anInt, sizeof(int));
out.write((char *)&aDouble, sizeof(double);
out.write(aCstring, 64 * sizeof(char));

anObject.Serialize(out); // Call anObject's Serialize function recursively


char zero = 0, one = 1;

if(aPointer)
{
out.write(&one, sizeof(char)); // Write a flag if aPointer is NULL or not

aPointer->Serialize(out);
}
else
out.write(&zero, sizeof(char));
}

void MyClass::Deserialize(std::istream & in)
{
in.read((char *)&anInt, sizeof(int));
in.read((char *)&aDouble, sizeof(double)0;
in.read(aCstring, 64 * sizeof(char));

anObject.Deserialize(in); // Deserialize anObject recursively


char flag;

in.read(&flag, sizeof(char));

if(flag)
{
aPointer = new SomeObject; // Or find a way to get the address of an existing SomeObject object

aPointer->Deserialize(in);
}
}


Then, to read/write the data, you just do something like:

int i;

int size = array.size();
ofile.write((char *)&size, sizeof(int)); // Write size, otherwise we don't know how big the array is when reading it in


for(i = 0; i < array.size(); i++) // Or, if you want, you can use std::for_each, but then you'll need to change the Serialize/Deserialize functions into functors

array[i].Serialize(ofile);

...

int size;
ifile.read((char *)&size, sizeof(int)); // Read size back in

array.resize(size);

for(i = 0; i < size; i++)
array[i].Deserialize(ifile);


Hope this helps.

[edited by - aprosenf on May 8, 2004 11:50:58 AM]

Share this post


Link to post
Share on other sites
Ok thank you very much, i was hoping it was possible , makes sense now if only an adress is being stored (bit long for a binary file but still, probably a list of adresses).
I wrote the classes scripted (i.e Push( params... )) so all I really need to do is sort out some sort of text scripting.

Thanks very much.

Share this post


Link to post
Share on other sites

  • Advertisement