Wiley.Symbian.OS.C.plus.plus.for.Mobile.Phones.Aug.2007 (779890), страница 44
Текст из файла (страница 44)
To cater for this, HBufC has aNewL() overload that takes a read stream and a maximum length asparameters and constructs a buffer of precisely the correct size to containthe data:const TInt KStreamsMaxReadBufLength = 10000;_LIT(KSampleText, "Hello world");TBuf<16> text = KSampleText;writer << text;...HBufC* newtext = HBufC::NewL(reader, KStreamsMaxReadBufLength);You should set the maximum length to be at least as large as thegreatest amount of data that you can reasonably expect to have tohandle. If the reader attempts to read more than the specified maximum,HBufC::NewL() leaves with the error KErrCorrupt.Externalizing and InternalizingYou can externalize and internalize any class that implements ExternalizeL() and InternalizeL(), which are prototyped as:class Foo{public:...void ExternalizeL(RWriteStream& aStream) const;void InternalizeL(RReadStream& aStream);...}For such a class, externalization can use either:Foo foo;writer << fooor:Foo foo;foo.Externalize(writer);220FILES AND THE FILE SYSTEMwhich are functionally equivalent.
Similarly, for internalization, you canuse either:Foo foo;reader >> foo;or:Foo foo;foo.Internalize(reader);The implementation of externalization and internalization functionsshould handle all data contained within the stream. In the following codefrom the Noughts and Crosses application, three classes in the projectimplement Externalize() and Internalize() functions and takeresponsibility for data associated with the designated task. The application UI class implementation calls Externalize() on the engineclass, which is responsible for the state of the game board: it writes thestate of each tile to the stream and writes the ID of the tile with the UIfocus.
The controller class is responsible for the input from the user; thisexternalize function records which player’s turn it is and the state of theturn.void COandXAppUi::ExternalizeL(RWriteStream& aStream) const/* Write the application UI’s state, which includes all of thegame state, to a writable stream.@param aStream is the stream to which the state is written.*/{iEngine->ExternalizeL(aStream);iController->ExternalizeL(aStream);aStream.WriteInt8L(iAppView->IdOfFocusControl() );}void COandXEngine::ExternalizeL(RWriteStream& aStream) const{for (TInt i = 0; i<KNumberOfTiles; i++){aStream.WriteInt8L(iTileStates[i]);}}void COandXController::ExternalizeL(RWriteStream& aStream) const{aStream.WriteUint8L(iState);aStream.WriteInt8L(iCrossTurn);}Internalization is performed by the same classes. The engine is internalized first, then the controller and finally the application UI classitself.STREAMS221void COandXAppUi::InternalizeL(RReadStream& aStream)/* Restore the game state from the supplied readable stream.@param aStream is the stream containing the game state.*/{iEngine->InternalizeL(aStream);iController->InternalizeL(aStream);ReportWhoseTurn() ;iAppView->MoveFocusTo(aStream.ReadInt8L() );}void COandXEngine::InternalizeL(RReadStream& aStream){for (TInt i = 0; i<KNumberOfTiles; i++){iTileStates[i] = aStream.ReadInt8L() ;}}void COandXController::InternalizeL(RReadStream& aStream){iState = (TState) aStream.ReadUint8L() ;iCrossTurn = aStream.ReadInt8L() ;}It should be clear from this discussion that both << and >> can leave.You will need to use them with a trap if they occur in a non-leavingfunction.We can see from the example stream code that the classes are veryprecise about data they are internalizing or externalizing.
In the controller code, the member variable iState takes 4 bytes of memoryin stack space although it is stored as an 8-bit unsigned integer andReadUint8L() and WriteUint8L() are used. This is because thenumber of states is pre-defined in the enumeration TState and cannever be negative. iCrossTurn, a TBool, again uses 4 bytes of stackspace but can be stored in a single byte as it can only have two values, 0and 1.Functions for Writing and Reading StreamsThe stream base classes provide a variety of functions (see Table 7.1) toread and write specific data types, ranging from 8-bit integers to 64-bitreal numbers.
These functions are called when you use << and >> onbuilt-in types. You should make explicit use of these functions only whenyou have to, as in the above example to deal with TInts, or when youwant to be very specific about how your data is externalized.222FILES AND THE FILE SYSTEMTable 7.1 Stream functionsRead and WriteStream functionsTypeExternal FormatReadL()WriteL()Data in internal formatReadL(RwriteStream&)WriteL(RReadStream&)Transfer from other stream typeReadInt8L()WriteInt8L()TInt88-bit signed integerReadInt16L()WriteInt16L()TInt1616-bit signed integer; bytes storedlittle-endianReadInt32L()WriteInt32L()TInt3232-bit signed integer; bytes storedlittle-endianReadUint8L()WriteUint8L()TUint88-bit unsigned integerReadUint16L()WriteUint16L()TUint1616-bit unsigned integer; bytesstored little-endianReadUint32L()WriteUint32L()TUint3232-bit unsigned integer; bytesstored little-endianReadReal32L()WriteReal32L()TReal3232-bit IEEE 754 single-precisionfloating pointReadReal64L()WriteReal64L()TReal,TReal6464-bit IEEE 754 double-precisionfloating pointThe stream base classes also provide a range of WriteL() andReadL() functions to handle raw data.
You need to be careful whenusing them because:• the raw data is written to the stream exactly as it appears in memory,so you must make sure that it is already in an external format beforecalling WriteL()• ReadL() must read exactly the same amount of data that was writtenby the corresponding WriteL(), perhaps by writing the lengthimmediately before the data, or terminating the data with a uniquedelimiter• you must implement a way of dealing with the maximum expectedlength of the data, say, by using the strategy described earlier forHBufC::NewL()• the 16-bit WriteL() and ReadL() functions don’t give you thestandard Unicode compression and decompression that you get whenyou use << and >>.STREAMS223The full range of WriteL() functions is:class RWriteStream{public:...IMPORT_C void WriteL(constIMPORT_C void WriteL(constIMPORT_C void WriteL(const...IMPORT_C void WriteL(constIMPORT_C void WriteL(constIMPORT_C void WriteL(const...}TDesC8& aDes);TDesC8& aDes, TInt aLength);TUint8* aPtr, TInt aLength);TDesC16& aDes);TDesC16& aDes, TInt aLength);TUint16* aPtr, TInt aLength);The WriteL(const TDesC8& aDes) function writes out all of thedata contained in the descriptor.
The next two functions write aLengthbytes, from the beginning of the descriptor and the location indicatedby the pointer, respectively. The 16-bit versions behave similarly, exceptthat they write Unicode characters instead of bytes.The corresponding set of ReadL() functions is:class RReadStream{public:...IMPORT_C void ReadL(TDes8& aDes);IMPORT_C void ReadL(TDes8& aDes, TChar aDelim);IMPORT_C void ReadL(TDes8& aDes, TInt aLength);IMPORT_C void ReadL(TUint8* aPtr, TInt aLength);IMPORT_C void ReadL(TInt aLength);...IMPORT_C void ReadL(TDes16& aDes);IMPORT_C void ReadL(TDes16& aDes, TChar aDelim);IMPORT_C void ReadL(TDes16& aDes, TInt aLength);IMPORT_C void ReadL(TUint16* aPtr, TInt aLength);...}The ReadL(TDes8& aDes) function reads aDes.MaxLength()bytes from the stream, exactly filling the descriptor.
The next functionreads the number of characters up to, and including, the first occurrenceof the specified delimiter character (if the delimiter is not read, it fillsthe descriptor). The following two functions read aLength bytes intothe descriptor or the memory location indicated by the pointer. The fifthfunction reads and discards aLength bytes. As with WriteL(), the16-bit versions have similar actions, but read Unicode characters ratherthan bytes.So far, we have seen that we can store the state of a game in astream and that stream may be stored in a file and persist between powercycles of a Symbian OS phone.
We can also see that the store could be224FILES AND THE FILE SYSTEMTable 7.2 Types of streamHeader fileClass namesMediums32file.hRFileWriteStream,RFileReadStreamA file; constructors specify either anopen RFile or a file server sessionand a file names32mem.hRDesWriteStream,RDesReadStreamMemory, identified by a descriptors32mem.hRMemWriteStream,RMemReadStreamMemory, identified by a pointer andlengths32mem.hRBufWriteStream,RBufReadStreamMemory, managed by a dynamicbuffer derived from CBufBase; asnew data is written through anRBufWriteStream, the destinationCBufBase is expanded as necessarys32std.hRStoreWriteStream,RStoreReadStreamA stream store; constructors specify astream store and a stream IDs32stor.hRDictionaryReadStream,RDictionaryWriteStreamA dictionary store; constructorsspecify a dictionary store and a UIDs32crypt.hREncryptStream,RDecryptStreamA stream; constructors specify the hoststream, the CSecurityBasealgorithm, and a string (a password) toinitialize the CSecurityBasememory based.