• We’re currently investigating an issue related to the forum theme and styling that is impacting page layout and visual formatting. The problem has been identified, and we are actively working on a resolution. There is no impact to user data or functionality, this is strictly a front-end display issue. We’ll post an update once the fix has been deployed. Thanks for your patience while we get this sorted.

Serialization & Reading/Write Multiple Lines :: MFC

kuphryn

Senior member
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().
 
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
 
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.
 
Thanks.

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

Kuphryn
 
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.
 
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
 



<< 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.
 

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.
 
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
 
Back
Top