Streams - externalizing objects on Symbian
This article provides an overview of Symbian streams - a mechanism to provide an external representation of one or more objects. A more complete coverage of the topic is provided in Fundamentals of Symbian C++/Streams And Stores
A Symbian C++ stream is the external representation of one or more objects.The process of externalization involves writing an object’s data to a stream, and the reverse process is termed internalization. The external representation may reside in one of a variety of media, including stores, files and in memory.
The external representation needs to be free of any peculiarities of internal storage – such as byte order, and padding associated with data alignment – that are required by the phone’s CPU, the C++ compiler or the application’s implementation. Clearly, it is meaningless to externalize a pointer; it must be replaced in the external representation by the data to which it points. The external representation of each item of data must have an unambiguously defined length.
For example, RFileWriteStream and RFileReadStream implement a stream that resides in a file, and RDesWriteStream and RDesReadStream implement a memory-resident stream whose memory is identified by a descriptor.
Storing multiple data items, which may be from more than one object, in a single stream implies that they are placed in the stream in a specific order.
void WriteToStreamFileL(RFs& aFs, TDesC& aFileName, TInt16* aInt)
writer.PushL(); // writer on cleanup stack
User::LeaveIfError(writer.Create(aFs, aFileName, EFileWrite));
writer << *aInt;
Once the file has been created, the data is externalized by using operator<<(). After writing, it is necessary to call the write stream's CommitL() to ensure that any buffered data is written to the stream. Only then can you remove the stream from the cleanup stack, using the stream's Pop() function. Finally, you need to call the stream's Release() to close the stream and free the resources it has been using.
Instead of calling Pop() and Release(), you could make a single call to the cleanup stack's PopAndDestroy(), which would achieve the same result.
Restores the objects by reading from the stream, must therefore follow exactly the same order that was used to externalize them.
void ReadFromStreamFileL(RFs& aFs, TDesC& aFileName, TInt16* aInt)
reader.PushL(); // reader on cleanup stack
User::LeaveIfError(reader.Open(aFs, aFileName, EFileRead));
reader >> *aInt;
CleanupStack::PopAndDestroy(); // reader
You can externalize and internalize any class that implements ExternalizeL() and InternalizeL(), which are prototyped as:
void ExternalizeL(RWriteStream& aStream) const;
void InternalizeL(RReadStream& aStream);
For such a class, externalization can use either:
writer << foo
Similarly, for internalization, you can use either:
reader >> foo;
The operators operator<< and operator>> are based on methods ExternilizeL() and InternalizeL() so these operators can leave. Do not use them without TRAP in a non-leaving function.