Serialization & Reading/Write Multiple Lines :: MFC

kuphryn

Senior member
Jan 7, 2001
400
0
0
Hello.

My intention is to read each line from a file and save it into a STL list of CString. So if there are 10 lines in the file, then the linked list of CString will be of size ten. Prosise demonstrates a very effective way to read and write from and to a file linewise using the CStdioFile class. However, in doc/view, MFC turns to Serialization. The problem, to me, with Serialization is I do not know what is going on in the background. I do not know what the framework does to the data in terms of CArchive.

When writing to CArchive, I use this:

for (iter = list.begin(); iter != list.end(); ++iter)
ar << *iter;

I am not sure how to read data from CArchive back into the linked list. First, I do not know whether data is stored similar to a file, i.e. if you write line1 and line2, then you can read back line1 and line2 in its original form.

How should I go about read data from CArchive back into the linked list if I have no knowledge of how CArchive manages the orientation of the data?

For example let say that the linked list of CString has this:

-----
a
b
c
d
e
-----

Okay. When it stores the data into CArchive, I assumpt it stores it like this:

<- a <- b <- c <- d <-e

However, if I have no prior knowledge of what was in the CArchive, how do I go about saving the data from CArchive back into the linked list?

Thanks,
Kuphryn

Note: If nothing works, I think the technique Prosise shows is best since class CStdioFile features ReadString() and WriteString().
 

Adrian Tung

Golden Member
Oct 10, 1999
1,370
1
0
CArchive also has ReadString and WriteString functions.

From the MSDN:

Bool ReadString(CString& rString );

LPTSTR ReadString( LPTSTR lpsz, UINT nMax );
throw( CArchiveException );

Return Value

In the version that returns Bool, TRUE if successful; FALSE otherwise.

In the version that returns an LPTSTR, a pointer to the buffer containing the text data; NULL if end-of-file was reached.

Parameters

rString

A reference to a CString that will contain the resultant string after it is read from the file associated with the CArchive object.

lpsz

Specifies a pointer to a user-supplied buffer that will receive a null-terminated text string.

nMax

Specifies the maximum number of characters to read. Should be one less than the size of the lpsz buffer.

Remarks

Call this member function to read text data into a buffer from the file associated with the CArchive object. In the version of the member function with the nMax parameter, the buffer will hold up to a limit of nMax - 1 characters. Reading is stopped by a carriage return-linefeed pair. Trailing newline characters are always removed. A null character ('\0') is appended in either case.



Hope that helps,
:)atwl
 

Argo

Lifer
Apr 8, 2000
10,045
0
0
You can't use serialization to read random strings. With serialization the class you read has to be the same as the one you wrote. Now, in the past I've bypassed this restriction, but it's more of a hack.
 

kuphryn

Senior member
Jan 7, 2001
400
0
0
Thanks.

Interesting. Serialization is similar to the read and write functions in core C++ when reading and writing in binary mode.

Kuphryn
 

CodeJockey

Member
May 1, 2001
177
0
0
What if you put fixed data first when storing the object, and always put the strings (which I assume may vary in number from one object to the next) last. The CArchive operator>> method throws an exception, so you should be able to use that. As a result, when loading the archive:

...
ar >> m_iAnint;
ar >> m_lALong;
...
CString str;
bool bDoneReading = false;
while ( !bDoneReading ) {
try {
ar >>str;
list.append( str ); //
}
catch (CException* e) {
// Failed to read string
bDoneReading = true;
}
}


Alternatively, you could store an integer in the archive indicating the number of strings, followed by the strings themselves. When loading the archive, you read the integer and then know exactly how many strings to expect.
 

kuphryn

Senior member
Jan 7, 2001
400
0
0
Nice! Thanks for those pointers.

I prefer the try-catch technique. The reason is with the nature of the program, the user can open any text file. it could contain any data. There is no way to know the size. The best way is to read each line (entire line) into a string and insert it into the linked list. That way, if the size of the linked list is 20, then there are 20 lines in the source file.

The try-catch might not work either because, again, the program will have no prior information about the content of the file.

ar >> MyCString;

The code above might store *everything* on that file into MyCString instead of the first line.

Kuphryn
 

CodeJockey

Member
May 1, 2001
177
0
0



<< The try-catch might not work either because, again, the program will have no prior information about the content of the file. >>



The CArchive is intended only for storing and loading an object to/from a file (in which case you had better know exactly what the contents of the file are, or should be). It is not intended for general file i/o.

Use a CFile, make your own class that inherits from CFile, or use CreateFile(), ReadFile(), and WriteFile() from the Platform SDK if you need to do more than simply store and load an object.
 

RSMemphis

Golden Member
Oct 6, 2001
1,521
0
0
A related question - do fopen, fprintf, etc get projected onto the SDK file operations?
 

CodeJockey

Member
May 1, 2001
177
0
0

It's amazing what you can find out by using the VC++ debugger. Yes, fopen() ultimately calls CreateFile(), although there are a few layers between them...the call stack is:

_sopen(const char * 0x0042401c `string', int 0, int 64) line 319
_openfile(const char * 0x0042401c `string', const char * 0x0042402d, int 64, _iobuf * 0x00426af0) line 193 + 22 bytes
_fsopen(const char * 0x0042401c `string', const char * 0x0042402c `string', int 64) line 68 + 21 bytes
fopen(const char * 0x0042401c `string', const char * 0x0042402c `string') line 104 + 15 bytes

with _sopen() being the function that calls CreateFile().

The other file i/o routines are likely implemented with a similar set of layers down to the underlying ReadFile() or WriteFile() calls.
 

Adrian Tung

Golden Member
Oct 10, 1999
1,370
1
0
I don't understand... why go through all the complications? Calling ReadString from a CArchive already reads a string of unknown length into a CString class... why delve deeper than that?


:)atwl