We help IT Professionals succeed at work.

We've partnered with Certified Experts, Carl Webster and Richard Faulkner, to bring you two Citrix podcasts. Learn about 2020 trends and get answers to your biggest Citrix questions!Listen Now

x

CFile and UNICODE

mrwad99
mrwad99 asked
on
Medium Priority
2,140 Views
Last Modified: 2013-11-20
Ah hello.

I am writing out a CMyClass object (very simple class, contains a couple of integers and a BOOL) using CFile

      CFile f;
      if( !f.Open( _T("C:\\Test.txt"), CFile::modeCreate | CFile::modeWrite | CFile::typeBinary ) ) ASSERT(FALSE);
      CMyClass myClass(1, 2, TRUE);
      f.Write((void*)&myClass, sizeof(myClass));

      f.Close();

      if( !f.Open( _T("C:\\Test.txt"), CFile::modeRead | CFile::typeBinary ) ) ASSERT(FALSE);
      CMyClass* pmyClass = new CMyClass();
      f.Read((void*)pmyClass, sizeof(CMyClass));

and all this works fine.

My concern is now that I am thinking about adding a CString member to the class, I dont want to break anything if the CString contains foreign characters.  

In short, is what I am currently doing going to be UNICODE safe ?

TIA
Comment
Watch Question

>> I am thinking about adding a CString member to the class
If you add CString then it won't work the same way.
AndyAinscowFreelance programmer / Consultant
CERTIFIED EXPERT

Commented:
What you are doing is storing the contents of the object.
>> CMyClass myClass(1, 2, TRUE);
>> f.Write((void*)&myClass, sizeof(myClass));

If you add CString
class CMyClass
{
   int x;
   CString str;
}

CMyClass::CMyClass()
{
   x = 10;        // 4 bytes
   str = "Hello world" // 11 bytes
}

You are expection the sizeof the object to be 15 (4+11).
But it is not, because CString just contains one pointer.

In that case you will just copy the pointer value.

Author

Commented:
>> If you add CString then it won't work the same way.

Hmm.  That is useful.  Care to elaborate on why ?

Andy:  thanks.  I think I saw that link before, and it made me decide to use serialisation instead.  Maybe that too is the answer here...

Author

Commented:
Thanks for that rajeev_devin.

Interestingly, I did try this, and I did notice that no matter how long the CString, the size was consistent.  The code did not crash however, and the read CString was the same as the stored CString.

Why could that have been ?

Author

Commented:
Overall, is there any way I can use CFile::Write and still output a string ?  Could I use a TCHAR[] or something ?

Or is serialisaion the only answer ?

TIA
Are you writing and reading in the same object ???
>> Overall, is there any way I can use CFile::Write and still output a string ?  Could I use a TCHAR[] or something ?
That is better.
You can use TCHAR array. But remember not pointer.
Something like this
class CMyClass
{
   int x;
   TCHAR[1000];
}
AndyAinscowFreelance programmer / Consultant
CERTIFIED EXPERT

Commented:
In CMyClass have two functions Read, Write each of which takes a CFile pointer.
That way the class takes care of itself - change the class, change the code inside the class.


Back to UNICODE.
I am not certain if the CFile class is *really* suitable with UNICODE - some things I read say it isn't, hence the link I posted.  It may allow you to write safe code inside the CMyClass where it reads/writes the UNICODE strings to the text file.

Author

Commented:
rajeev_devin

This is my code:

class CMyClass : public CObject
{
 public:
      CMyClass() {}
      CMyClass(int i, int j, BOOL b, CString str)
      {
            m_n1 = i;
            m_n2 = j;
            m_bBOOL = b;
            m_strString = str;
      }
      virtual ~CMyClass(void) {};
      
      int m_n1, m_n2;
      BOOL m_bBOOL;
      CString m_strString;
};

//...

      if( !f.Open( _T("C:\\Test.txt"), CFile::modeWrite | CFile::modeCreate | CFile::typeBinary )) ASSERT(FALSE);
      CMyClass myClass( 10, 20, TRUE, _T("This is my string") );
      f.Write((void*)&myClass, sizeof(myClass));
      size_t size = sizeof(myClass);
      f.Close();

      if( !f.Open( _T("C:\\Test.txt"), CFile::modeRead | CFile::typeBinary ) ) ASSERT(FALSE);
      CMyClass* pmyClass = new CMyClass();
      f.Read((void*)pmyClass, sizeof(CMyClass));

And this works fine!  'pmyClass' has the same values as 'myClass' !

?!
AndyAinscowFreelance programmer / Consultant
CERTIFIED EXPERT
Commented:
Look at test.txt with notepad - see what has been written.

Now do something really dim and change the order of the variables and read the file (don't overwrite it first).  IMHO it is safer (and better coded?) to encapsulate the read/write inside the CMyClass itself.  Changes you then make to CMyClass are hidden from the rest of the app, you don't need to search all over the place for code snippets to update.

Not the solution you were looking for? Getting a personalized solution is easy.

Ask the Experts
This is correct the value will be same. Why?
Because in both case CString in pointing to the same address.

Author

Commented:
Yes, that is an excellent point.  Also, what if I add new members ?  That screws it up totally.

I think serialisation with versioning is the way to go.

I will close this once feedback is received as to why the code I posted works, when in theory it should not.

Thanks.
>> CMyClass myClass( 10, 20, TRUE, _T("This is my string") );
>> f.Write((void*)&myClass, sizeof(myClass));
>> f.Close();
CString of myClass is pointing to a location that you are storing using Write.

>> if( !f.Open( _T("C:\\Test.txt"), CFile::modeRead | CFile::typeBinary ) ) ASSERT(FALSE);
>> CMyClass* pmyClass = new CMyClass();
>> f.Read((void*)pmyClass, sizeof(CMyClass));
Now the CString of pmyClass has the same address as myClass.
Therefore, it is pointing to the same data.

I hope its clear.

Author

Commented:
>> Because in both case CString in pointing to the same address

Sorry, I dont get that.  What CString are you talking about ?  I construct two objects, so each has a different address.

?
>> Yes, that is an excellent point.
It is like that.
If you want to see the difference then in your program just read the value of that file.
You will see that the CString is garbage.

Do this

CFile f;
if( !f.Open( _T("C:\\Test.txt"), CFile::modeRead | CFile::typeBinary ) ) ASSERT(FALSE);
CMyClass* pmyClass = new CMyClass();
f.Read((void*)pmyClass, sizeof(CMyClass));
AndyAinscowFreelance programmer / Consultant
CERTIFIED EXPERT

Commented:
mrwad99 - you might have missed my last comment.
>> Sorry, I dont get that.  What CString are you talking about ?
Simple example. I am excluding the ctor and dtor.

class CMyClass {
   m_strString; // It is pointing to the string in location say 1000.
};

CMyClass myClass("This is a test");
write(&myClass, ...);

CMyClass* pmyClass = new CMyClass();
Read(pmyClass, sizeof(CMyClass));

value of

pmyClass
{
   // 1000 which is the same string.
}

Author

Commented:
Ha !

I absolutely see the problem.  Adding an explicit call to

      myClass.~CMyClass();

before reading back from the file shows that pmyFile has an m_strString member that is full of rubbish.

Overall, I am going to use serialisation, mainly as a result of what Andy said about adding/changing variables etc.

Thanks both, I will close this now :)
>> I construct two objects, so each has a different address.
As I said before CString class only contains a pointer. Something like this

CString {
   char* data; // Here is the pointer.
}

Therefore its size will be 4. Always
I don't know whether the thing is clear to you ?

Author

Commented:
I have posted a follow on to this at http:Q_21795040.html

Any participation welcome :)

Author

Commented:
rajeev_devin: yes, your explanation was excellent.  I understand why I cannot use CString in the manner I was doing.  Thank you.
Access more of Experts Exchange with a free account
Thanks for using Experts Exchange.

Create a free account to continue.

Limited access with a free account allows you to:

  • View three pieces of content (articles, solutions, posts, and videos)
  • Ask the experts questions (counted toward content limit)
  • Customize your dashboard and profile

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.