File, Streams and Stores
| Fri, 2005-06-24 08:43 | |
|
|
A few definitions regarding files, streams and store (taken from this post by Didster): Files: Just plain old binary files, where you the developer are responsable for writting everything to that file in the correct format that you need to get data back out. For instance, if you write a descriptor to the file, you would need to write a flag indicating its type (8 or 16 bit), it's length, its maxlength if its non-constant, and its data to reconstruct it from the file. Code: /* Txt file to be opened. */ RFile file ; file.Open(aFs, aFilename,EFileRead) ; CleanupClosePushL(file); /* Size of file. */ TInt iSize ; file.Size(iSize) ; /* Allocate enough memory to read in the whole file. */ HBufC8* buf = HBufC8::NewL(iSize) ; /* Get a pointer to modify contents of buffer. */ TPtr8 pBuf = buf->Des() ; /* Read data into buf. */ file.Read(pBuf) ; CleanupStack::PopAndDestroy() ; // file Streams: Provide a simple API for you to write data in external format and to allow you to abstract the underlying storage away from your code. For instance, you can attach a stream to a file, or to a block of memory, but reading and writting to it remain the same. Also, the bit above about writting lengths etc is done for you - when you send a descriptor to a stream, everything needed to reconstruct it is written for you. This is because the descriptor classes serialise themselfs - they provide an Externalise and Internalise method which the framework calls when one of them is added to a stream - in these method they write and read all their own data members. This process is known as serialisation, ever done MFC? Then think CArchive - basically its about making it a classes own responsabilty to save and load thier state. Code: // // Open a RFs RFs aFs; User::LeaveIfError(aFs.Connect()); CleanupClosePushL(aFs); _LIT(KStreamName, "C:\\TestStream.dat"); // // Delete old file aFs.Delete(KStreamName); // // Open a file write stream RFileWriteStream fWrite; User::LeaveIfError(fWrite.Create(aFs, KStreamName, EFileWrite)); CleanupClosePushL(fWrite); // // Write to the stream and commit it _LIT(KTextToCopy, "This is a test stream"); fWrite << KTextToCopy(); // Warning, this _CAN_ leave fWrite.CommitL(); // // Close the stream CleanupStack::PopAndDestroy(&fWrite); // // Open a read stream RFileReadStream fRead; User::LeaveIfError(fRead.Open(aFs, KStreamName, EFileRead)); CleanupClosePushL(fRead); // // Read data back from the stream. Using the HBufC::NewL which takes a RReadStream // so we get a buffer exactly the right size for whats in the stream HBufC* pBuf = HBufC::NewL(fRead, 1000); // // Close the read stream CleanupStack::PopAndDestroy(&fRead); // // Close the RFs CleanupStack::PopAndDestroy(&aFs); Stores: Streams are great, but they have one problem. They are sequentially accessed. In that you must know the exact order thinks went in to get them out. So say if you have two classes in your stream, A and B. When you load from that stream, if you want B, you must first load A even if you don't want it. Stores get round this. Essentially, they are a network of streams - mutiple streams which are individually accessable from there "stream id". The stream id's are maintained by a dictonary at the start of the store. Code: // // A class for correct cleanup of RPointerArrays template <class T> class CleanupResetAndDestroyClose { public: inline static void PushL(T& aRef) {CleanupStack::PushL(TCleanupItem(&Close,&aRef));} static void Close(TAny *aPtr) { (STATIC_CAST(T*,aPtr))->ResetAndDestroy(); (STATIC_CAST(T*,aPtr))->Close(); } }; template <class T> inline void CleanupResetAndDestroyClosePushL(T& aRef) {CleanupResetAndDestroyClose<T>::PushL(aRef);} // // A class we wish to put into the store class CFoo : public CBase { public: CFoo() {} TBuf<20> iName; TInt iSomeData; TStreamId StoreL(CStreamStore& aStore) const; void ExternalizeL(RWriteStream& aStream) const; void RestoreL(CStreamStore& aStore,TStreamId anId); void InternalizeL(RReadStream& aStream); }; // // Create a stream, and externilize ourselfs into it TStreamId CFoo::StoreL(CStreamStore& aStore) const { RStoreWriteStream outstream; TStreamId id = outstream.CreateLC(aStore); ExternalizeL(outstream); outstream.CommitL(); CleanupStack::PopAndDestroy(&outstream); return id; } void CFoo::ExternalizeL(RWriteStream& aStream) const { aStream << iName; aStream.WriteInt16L(iSomeData); } // // Open up the given stream, and restore from it void CFoo::RestoreL(CStreamStore& aStore,TStreamId anId) { RStoreReadStream stream; stream.OpenLC(aStore,anId); InternalizeL(stream); CleanupStack::PopAndDestroy(&stream); } void CFoo::InternalizeL(RReadStream& aStream) { aStream >> iName; iSomeData = aStream.ReadInt16L(); } // // Add each record to the store void DoSaveToStoreL(CFileStore* aStore) { RPointerArray<CFoo> rObs; CleanupResetAndDestroyClosePushL(rObs); CFoo* pFoo1 = new CFoo; CleanupStack::PushL(pFoo1); pFoo1->iName.Copy(_L("Test Ob1")); pFoo1->iSomeData = 1; User::LeaveIfError(rObs.Append(pFoo1)); CleanupStack::Pop(pFoo1); CFoo* pFoo2 = new CFoo; CleanupStack::PushL(pFoo2); pFoo2->iName.Copy(_L("Test Ob2")); pFoo2->iSomeData = 2; User::LeaveIfError(rObs.Append(pFoo2)); CleanupStack::Pop(pFoo2); RArray < TStreamId > rIndexArray; CleanupClosePushL(rIndexArray); // // Store each object from rObs into the store. Each object will create it's own stream // in the store, and it's id will be returned from ->StoreL. We then store the ids in a // index which we store in the root stream of the store. for(TInt n = 0; n < rObs.Count(); ++n) { TStreamId id = rObs[n]->StoreL(*aStore); User::LeaveIfError(rIndexArray.Append(id)); } // // Write index RStoreWriteStream rs; rs.ReplaceLC(*aStore, aStore->Root()); rs.WriteInt16L(rIndexArray.Count()); for(TInt nn = 0; nn < rIndexArray.Count(); ++nn) { // // Write name rs << rObs[nn]->iName; // // And index rs << rIndexArray[nn]; } rs.CommitL(); CleanupStack::PopAndDestroy(&rs); // // Commit the store aStore->CommitL(); // // Done with the index array CleanupStack::PopAndDestroy(&rIndexArray); // // And the objects CleanupStack::PopAndDestroy(&rObs); } LOCAL_C void doExampleL() { // // Open a RFs RFs aFs; User::LeaveIfError(aFs.Connect()); CleanupClosePushL(aFs); _LIT(KStoreName, "C:\\TestStore.dat"); // // Create a perminate file store CPermanentFileStore* pStore = CPermanentFileStore::ReplaceLC(aFs, KStoreName, EFileWrite); pStore->SetTypeL(KPermanentFileStoreLayoutUid); // // Write a fake root stream containg 0 for the entry count RStoreWriteStream rs; TStreamId id = rs.CreateLC(*pStore); rs.WriteInt16L(0); rs.CommitL(); pStore->SetRootL(id); pStore->CommitL(); CleanupStack::PopAndDestroy(&rs); // // Generate some objects and save them to the store TRAPD(err, DoSaveToStoreL(pStore)); if(err != KErrNone) { pStore->Revert(); User::Leave(err); } // // The store now contains a series of streams, and each stream contains it's own CFoo, which // we can load independatly of each other // // Close the store CleanupStack::PopAndDestroy(pStore); // // Open up the store for reading CPermanentFileStore* pReadStore = CPermanentFileStore::OpenLC(aFs, KStoreName, EFileRead); // // Go through the ids, and look for the one called Test Ob2 to demonstrate // we don't need to load Test Ob1 to get at Test Ob2 as we would if we were // using a normal stream TInt nRecordCount = 0; RStoreReadStream streamIn; streamIn.OpenLC(*pReadStore, pReadStore->Root()); nRecordCount = streamIn.ReadInt16L(); TStreamId nTheId; for(TInt n = 0; n < nRecordCount; ++n) { // // Read name TBuf<20> iName; streamIn >> iName; TStreamId id; streamIn >> id; if(iName.Compare(_L("Test Ob2")) == 0) { // // Found it! nTheId = id; break; } } CleanupStack::PopAndDestroy(&streamIn); if(nTheId != KNullStreamId) { // // Load er back in CFoo* pOb2 = new CFoo; CleanupStack::PushL(pOb2); // // Restore it pOb2->RestoreL(*pReadStore, nTheId); // // Do something with it // . // , // // Destory it CleanupStack::PopAndDestroy(pOb2); } // // Close the store CleanupStack::PopAndDestroy(pReadStore); // // Close the RFs CleanupStack::PopAndDestroy(&aFs); } Eric Bustarret |






Forum posts: 68
Well done heroes
Nikolas.
If we fall down it's so we can learn to pick ourselves up.
Forum posts: 9
It is very helpful for me.
qiangsir.
I love symbian.
Forum posts: 56
regards
arun
Forum posts: 1379
didster
Forum posts: 1
I have a piece of code:
RStoreWriteStream writeStream;
CleanupClosePushL(writeStream);
RFs fs;
User::LeaveIfError( fs.Connect() );
_LIT( KStreamStoreName, "C:\\Test.txt" );
CFileStore* store = CPermanentFileStore::ReplaceLC( fs, KStreamStoreName, EFileShareAny );
TStreamId id = writeStream.CreateLC( *store );
This code works fine with my friend but I get System error -18 from the CreateLC line. I have reinstaled my S80 SDK and the same problem is also with S60 2nd Ed. I also check that my hard disk is not full. Anyone can explain? Thank you.
Forum posts: 29
Is it posible to do something like File Mapping (CreateFileMapping(...) ) in Win32 , to get a pointer to the raw data in memory (file).
Thank you.
Vladan Markovic
Forum posts: 38
Forum posts: 3
I have compressed video file in my PC. I have to send 1kb of data
from file to the blutooth dvice ( Nokia6630) memroy.
For that any symbian API is there or other wise how can I write a piece code for that ,
Can you please suggest me.
Thanks.
Forum posts: 3
I tried a 20KB .jpg file and it didn't work.
Can somebody help me?
Forum posts: 98
Problem was in my video ring toner application i used stream store to read and write current setting of application done by user(volume ,video name e.t.c).
My problem is that if
I am using following way to hold setting file location
_LIT(KSettingFilePath,"C:\\setting.txt");
no problem
but if i store setting.txt in current application folder (C:\\system\\apps\\testplayer\\)
then reading and writing still works fine. but strangely when incoming call arrives call watcher object nowplays video but this time video hangs for one second in middle.
How is it possible?
What is the actual mistake done by me or is it a known issue on symbian(API bug)
I am only chanfging following line
_LIT(KSettingFilePath,"C:\\setting.txt");
to
_LIT(KSettingFilePath,"C:\\system\\apps\\testplayer\\\setting.txt");
and bug is introduced.
Plz suggest me..
Thanks
Forum posts: 36
_LIT(KSettingFilePath,"C:\\system\\apps\\testplayer\\\setting.txt");
Forum posts: 98
Forum posts: 41
RFile file ;
file.Open(aFs, aFilename,EFileRead) ;
//////////// CleanupClosePushL(file);
/* Size of file. */
TInt iSize ;
file.Size(iSize) ;
/* Allocate enough memory to read in the whole file. */
HBufC8* buf = HBufC8::NewL(iSize) ;
/* Get a pointer to modify contents of buffer. */
TPtr8 pBuf = buf->Des() ;
/* Read data into buf. */
file.Read(pBuf) ;
////////////CleanupStack::PopAndDestroy( //; // file
file.close();
ls the above program correct? I have just replaced CleanupStackPushL & PopandDestroy statement by a file.close statement at the end ?
Forum posts: 194
But why? What are you hoping to achieve?
If you don't call CleanupClosePushL() and HBufC8::NewLC() leaves then what happens to your file handle?
Forum posts: 4
CRichText::ExternalizeL(...) does not work !!!
i found lots of posts from people that had problems with this ... and nobody made it work correctly (all the time it throws some undocumented panic which i was not able to find in symbian include headers)
create a new store instead and to save datam fro rich text use
CRichText::StoreL(...)