Writing data on a file

Hi,
I am working on a MFC application witch needs to store data on a file

Here in my App


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include "stdafx.h"
#include "test_mfc.h"
#include "test_mfcDlg.h"
#include "afxdialogex.h"
#include "a.h"
# include <fstream>

class Client
{
public:
	Client(CString Name , CString LastName , CString Id , bool HasCheckingAcc = false , bool HasSavingAcc = false );
	int create();

	CString name;
	CString lastName;
	CString id;
	bool hasCheckingAcc;
	bool hasSavingAcc;
};



Client::Client(CString Name , CString LastName , CString Id , bool HasCheckingAcc , bool HasSavingAcc )
{
	name = Name;
	lastName=LastName;
	id=Id;
	hasCheckingAcc=HasCheckingAcc;
	hasSavingAcc=HasSavingAcc;
}

void displayMessage(CString message , CString title=L"Meesage")
{
	MessageBox(NULL,message,title,MB_OK | MB_ICONERROR);
}

//some other parts ...

void Ctest_mfcDlg::OnBnClickedButton2()
{
	Client myCl(L"Name",L"D",L"11111");
	Client myCl2(L"N2",L"D2",L"22222");


	wofstream output;
	output.open("12345566.test" , ios::binary);
	if( output.fail() )
	{
		CString mess;
		mess = strerror( errno );
		displayMessage(mess);	
	}

	output.write( (wchar_t *) &myCl , sizeof(myCl));
	output.close();


	wifstream input;
	input.open("12345566.test" , ios::binary  );
	if(! input.fail())
	{


	input.read( (wchar_t *) &myCl2 , sizeof(myCl2));
	CString mess;
		mess.Format(L"Name:%s\nID:%s",myCl2.name,myCl2.id );
		displayMessage(mess);	
	}

	else
	{
		CString mess;
		mess = strerror( errno );
		displayMessage(mess);	
	}


}


When i run the app and click on button I got this message box:
Name:N2
ID:22222

But I expect it to be
Name:Name
ID:11111

What is wrong with this app?
edit: I used char * and ofstream and it's working well (this part solved , just second question is remained)



And , How can I write data to file using a function inside of my class?

Thanks
Last edited on
Hello.
I think, your main problem is trying to serialize/deserialize your object using wide stream.
wifstream::read uses its second parameter as number of characters to read. But you should take into account that every wchar_t can be 1, 2, or 4 bytes depending on operating system and compiler. So using there simply sizeof(myCl) can drive you into trouble.
In fact, the best decision will be to use char streams to write/read objects to/from file.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
	ofstream output;
	output.open("12345566.test" , ios::binary);
	if( output.fail() )
	{
		CString mess;
		mess = strerror( errno );
		displayMessage(mess);	
	}

	output.write( (char *) &myCl , sizeof(myCl));
	output.close();

	ifstream input;
	input.open("12345566.test" , ios::binary  );
	if(! input.fail())
	{
		input.read( (char *) &myCl2 , sizeof(myCl2));
		CString mess;
		mess.Format(L"Name:%s\nID:%s",myCl2.name,myCl2.id );
		displayMessage(mess);	
	}
	else
	{
		CString mess;
		mess = strerror( errno );
		displayMessage(mess);	
	}

So reading and writing runs byte-by-byte.

By the way, as I know, MSVC and GCC compilers store pointer to virtual methods table on negative offsets from object pointer, so serializing of objects vith virtual methods like that can offer you a bit of headache because of breaking of objects.
Last edited on
Thanks for reply.
That was problem

for reading Data I have created a function like this inside of my Client Class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int update(Client & myClient)
//also tried passing by value : int update(Client myClient)
{
	ifstream input;
	input.open("12345566.test" , ios::binary );
	if( input.fail() )
	{
		CString mess;
		mess = strerror( errno );
		displayMessage(mess);
		return 1 ;//anything but 0
	}

	
	input.read( (char *) &myClient , sizeof(myClient));
	input.close();

	return 0;
}


And I use function Like this:
1
2
3
Client myClient(L"Name",L"D",L"11111");//values are not importnat

myClient.update(myClient);



But I got this error when i run the function (in debuging )
Unhandled exception at 0x5adfab2a (mfc100ud.dll) in MyProject.exe: 0xC0000005: Access violation writing location 0x039708fc.


What is the problem?
Last edited on
Wariable errno staggers me, I don't see, where it comes from. I am not familiar with MFC, though, maybe it's born there. But I can tell you, that ifstream/ofstream won't change any global variables to report you an error message, so I assume you sould write error text by yourself in place of errno.

To the problem. You see, your update method works onlu with its parameter and doesn't need this pointer. So you should definitely make this method static. My point is when you call non-member method on your object and try to rewrite this object, you get an access violation. So try to make it static and tell me, if it goes right way.
I'd use MFC own CArchive class instead of that:
http://msdn.microsoft.com/en-us/library/caz3zy5s(v=vs.100).aspx

If you already use a complex framework like MFC, why you don't use the features you have ?


Mixing MFC classes with C++ STL classes is bad style. MFC has classes like CFile which you could use instead of std::ifstream.
http://msdn.microsoft.com/en-us/library/60fh2b6f(v=vs.80).aspx
Thanks for replies


\
To the problem. You see, your update method works onlu with its parameter and doesn't need this pointer. So you should definitely make this method static. My point is when you call non-member method on your object and try to rewrite this object, you get an access violation. So try to make it static and tell me, if it goes right way.

Unfortunately , making method static didn't change any thing ...
Is there any way not to have any arguments and make changes in current object?


I'd use MFC own CArchive class instead of that:
http://msdn.microsoft.com/en-us/library/caz3zy5s(v=vs.100).aspx

If you already use a complex framework like MFC, why you don't use the features you have ?

These data must be accessible on another native application which I am developing ...
Last edited on
Is there any way not to have any arguments and make changes in current object?

Well, you can don't pass any parameter to method and use inside this, because it's a pointer to the current object, but I believe, rewriting data by-byte isn't good style anyway, especially in member method through this ptr.
I've managed to get rid of exception by defining of second client in a different way:
Client* myCl2 = (Client*)new char[sizeof(Client)];
Here, as you can see, myCl2 points to a block of memory with needed size, and not to really created object. Of course, you should fill it before making any call to it's members, that's why non-static member isn't really an option.

If I were you, I would make a static method like that:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Client* Client::deserialize()
{
	ifstream input;
	input.open("12345566.test" , ios::binary );
	if( input.fail() )
	{
		CString mess;
		mess = strerror( errno );
		displayMessage(mess);
		return NULL;
	}

	char* client = new char[sizeof(Client)];
	input.read(client, sizeof(Client));
	input.close();
	return (Client*)client;
}


And if you will do some more complex serialization, you should read this: http://www.parashift.com/c++-faq-lite/serialization.html

Hope this will help.
Last edited on
Thanks a lot,
How can I use this function?
I tried
1
2
Client myClient(L"",L"",L"");
myClient = Client::update(myClient);//my function is static 

But It seems not to be correct.
Last edited on
Function returns pointer, so
Client* myClient = Client::update();

And dont forget to do
delete myClient;
when you've finished to work with it!

PS. If you feel you're not familiar with pointers or some other part of language, I advise you to grab some good book on C++ and read it carefully. And walk through C++-faq linked by me above, there are many interesting things there for any programmer.
Last edited on
Thanks
I tried this
1
2
3
4
5
	Client myClient(L"",L"",L"");
	//myClient.update(myClient);
	Client* myCl = Client::update(myClient);
	myClient = *myCl;
	displayMessage(myClient.name);// i made name public .... 

But I got Access violation error
Is it wrong?
Last edited on
I also tried
1
2
	Client* myCl = Client::update(myClient);
	displayMessage((*myCl).name);

But I got Access violation error ....
Well, post please your current version of update. I can't realize, why is there a parameter and what are you doing inside that method.
my update is same as this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Client* Client::update()
{
	ifstream input;
	input.open("12345566.test" , ios::binary );
	if( input.fail() )
	{
		CString mess;
		mess = strerror( errno );
		displayMessage(mess);
		return NULL;
	}

	char* client = new char[sizeof(Client)];
	input.read(client, sizeof(Client));
	input.close();
	return (Client*)client;
}


and I use it like:
1
2
Client* myCl = myClient.update();//i made function a none-static one
	displayMessage(myClient.name);


And I got Access violation error
I really advice you to read some teach-book on C++ to understand all basic concepts before moving somewhere.
Do you understand difference between static method and non-static one? If so, do you see any using of this pointer in method body? In oter words, does call to update uses myClient in any way? If not, this method should be static.

To the error. I can't reproduce it. Can you post error message here and tell, in which line does it occure?
Well , Let's start a new application
A simple one
I have a dialog and just one button in it:
and here is all of my code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

class Client
{
public:
	Client(string Name , string LastName , string Id , bool HasCheckingAcc = false , bool HasSavingAcc = false );
	int create();

	string name;
	string lastName;
	string id;
	bool hasCheckingAcc;
	bool hasSavingAcc;
};



Client::Client(string Name , string LastName , string Id  , bool HasCheckingAcc , bool HasSavingAcc )
{
	name = Name;
	lastName=LastName;
	id=Id;
	hasCheckingAcc=HasCheckingAcc;
	hasSavingAcc=HasSavingAcc;
}

void displayMessage(CString message , CString title=L"Meesage")
{
	MessageBox(NULL,message,title,MB_OK | MB_ICONERROR);
}

//on butten clicked:

Client myCl("aa","D","11111");
Client myCl2("aa2","D2","22222");


ofstream output;
output.open("12345.test" , ios::binary);
if( output.fail() )
{
	CString mess;
	mess = strerror( errno );
	displayMessage(mess);	
}

output.write( (char *) &myCl , sizeof(myCl));
output.close();


ifstream input;
input.open("12345.test" , ios::binary  );
if(! input.fail())
{


input.read( (char *) &myCl2 , sizeof(myCl2));
CString mess;
	mess.Format(L"Name:%s\nID:%s",myCl2.name,myCl2.id ); // here is where I get this error:
	//Unhandled exception at 0x5ed2b1d0 (msvcr100d.dll) in test_mfc.exe: 0xC0000005: Access violation reading location 0xcc006161.
	displayMessage(mess);	
	input.close();
}

else
{
	CString mess;
	mess = strerror( errno );
	displayMessage(mess);	
}



error is :Unhandled exception at 0x5ed2b1d0 (msvcr100d.dll) in test_mfc.exe: 0xC0000005: Access violation reading location 0xcc006161.
at line 62.
What Can the problem be?
Last edited on
Use c_str() method, CString ::Format expects a regular C style string as argument for "%s", not a std::string as you do.

mess.Format(L"Name:%s\nID:%s",myCl2.name.c_str(), myCl2.id.c_str() );
Topic archived. No new replies allowed.