I am trying to do a program take allow me to save data into a file.....as persistent data....and it will remain in the phone after close the program and reopen it...... but I am not so sure what I do is correct or not.......
I am using RFile to write to file and read frm file.....But I found out there are CFileStore(many ppls use it to store data) and file stream...
What the different between CFileStore and RFile? And can I know why v use the RFileReadStream and RFileWriteSteam?What the advantages and disadvantages of file stream and RFile.
any example code on file stream?is it we need to use the file stream together with the file store?
Anyone can explain? Don't need to answer all my question.I will appreciate it if u answer one of it.....
I am trying to create a application that will be used by other program to save high score. I am using the RFile to write and read file now....but i am asked to do it using file stream now.....is it file stream must used together with File store or RFile.
The code below is used by me to write to a file (C:\\System\\apps\\testdata\\testdata.dat).
it write data to the file, but when I want to read it using RFileReadStream.It show me system error so I try to use RFile::Read();(file interface) instead of RFileReadStream ...and it's work....anyone know why?
FileStores (and the whole file stream interface) is a layer that is built upon RFile and that adds a specific format to the saved data (ex: a dictionnary to handle multiple streams in the same store). Based on that, it is clear that you can not open with the stream interface a file that you have generated using RFile primitives (unless you have created the exact same format that the one expected by the stream primitives).
I don't really understand why you have to open your file with those primitive if you create it with RFile. My advice would be: - change your code and create your file using the stream primitive and everything would be fine. - or check that you really have to use the stream interface.....
Eric Bustarret
NewLC Founder & CEO / Professional Symbian OS Consultant
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.
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.
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.
Finally, on top of stores, you have DBMS. Which uses the store principle to implment a complete relational database system.
To complement the code already here, here is some very simple code to read the contents of a file into a heap-based descriptor. I've put that code in the OpenFileL method of my document class (which explains where the parameters in the Open method come from).
  /* Txt file to be opened. */   RFile file ;   file.Open(aFs, aFilename,EFileRead) ;
  /* Size of file. */   TInt iSize ;    file.Size(iSize) ;     /* Allocate enough memory to read in the whole file. */   HBufC8* buf = HBufC8::NewLC(iSize) ;
  /* Get a pointer to modify contents of buffer. */   TPtr8 pBuf = buf->Des() ;
  /* Read data into buf. */   file.Read(pBuf) ;
  file.Close() ;
  /* When buf is not needed anymore... */   CleanupStack::PopAndDestroy() ;
If we fall down it's so we can learn to pick ourselves up.
Great... I will add all this in the sticky topic with the definitions. (Nikolas, don't forget to put your file on the CleanupStack just after opening it - CleanupClosePushL(file) - since the HBufC allocation may leave, and same for sree where the iFileServer should be on the cleanupstack - but it looks like this is just a data member of a class just copied in the example so this is probably ok anyway ).
Who can do this for the stream and store interfaces
Eric Bustarret
NewLC Founder & CEO / Professional Symbian OS Consultant
// // 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);
I will do one for stores this avo if I get a spare minute, since it's a bit more involved.
And here you go for stores. This is a pretty simple example, that demonstrates the fact that unlike streams, you can load any object from the store when you want it. It doesn't demonstrate defered loading (TSwizzle's + CStoreMap)
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(); } };
// // 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); }
// // 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;
Forum posts: 5
Forum posts: 2133
RFiles and CFileStores have their pros and cons.... it really depends on what you need.
Eric
Eric Bustarret
NewLC Founder & CEO / Professional Symbian OS Consultant
Forum posts: 5
I am trying to create a application that will be used by other program to save high score. I am using the RFile to write and read file now....but i am asked to do it using file stream now.....is it file stream must used together with File store or RFile.
The code below is used by me to write
to a file (C:\\System\\apps\\testdata\\testdata.dat).
---------------------------------------------------------------------------
void CTestdataAppUi::Write()
{
TBuf8<KTestLength> buf;
RFs TheFs;
RFile file;
User::LeaveIfError(TheFs.Connect());
User::LeaveIfError(file.Open(TheFs,KTestFile,EFileWrite));
RFile f=file;
RFileWriteStream out(f);
TInt iFileSize;
file.Size(iFileSize);
out.Attach(file, iFileSize);
out.WriteL(KTestDes);
out.CommitL();
out.Close();
TheFs.Close();
}
--------------------------------------------------------------------------------
it write data to the file, but when I want to read it using RFileReadStream.It show me system error so I try to use RFile::Read();(file interface) instead of RFileReadStream ...and it's work....anyone know why?
Thanks in advance.
Forum posts: 67
well the wheel has gone full turn and i'm having exactly the same dilema...
I talked to some guys on irc (#symbian.dev on EFnet) and we haven't figured yet what exactly is the problem.
However they were a few conjectures:
Using a readstream to read from a file that does not contain a filestore is random.
Using a readstream to read from a file that has not been written to with a writestream is random.
Will let you know when I understand this better...
Take care,
Nikolas.
If we fall down it's so we can learn to pick ourselves up.
Forum posts: 2133
FileStores (and the whole file stream interface) is a layer that is built upon RFile and that adds a specific format to the saved data (ex: a dictionnary to handle multiple streams in the same store). Based on that, it is clear that you can not open with the stream interface a file that you have generated using RFile primitives (unless you have created the exact same format that the one expected by the stream primitives).
I don't really understand why you have to open your file with those primitive if you create it with RFile. My advice would be:
- change your code and create your file using the stream primitive and everything would be fine.
- or check that you really have to use the stream interface.....
Eric Bustarret
NewLC Founder & CEO / Professional Symbian OS Consultant
Forum posts: 1379
A few definations.
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.
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.
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.
Finally, on top of stores, you have DBMS. Which uses the store principle to implment a complete relational database system.
didster
Forum posts: 31
In order to have access to files first you connect to fileserver with which can have access to file operations:
Example code for read:
RFs iFileServer;
User::LeaveIfError(iFileServer.Connect());
RFile fp;
TInt err = fp.Open(iFileServer,_L("temp.txt"),EFileRead);
if(err !=KErrNone)
break;
TBuf8<10> buf;
TBuf16<200> buf16;
TBuf16<10> tmp16;
TInt Err;
Err = fp.Read(buf);
while(!Err && buf.Length()>0)
{
tmp16.Copy(buf);
buf16.Append(tmp16);
Err = fp.Read(buf);
}
iAppContainer->PrintData(buf16);
fp.Close();
iFileServer.Close();
Example code for File write:
RFs iFileServer;
User::LeaveIfError(iFileServer.Connect());
RFile fp;
TInt err = fp.Open(iFileServer,_L("temp.txt"),EFileWrite);
if(err !=KErrNone)
fp.Create(iFileServer,_L("temp.txt"),EFileWrite);
TInt pos=0 ;
fp.Seek(ESeekEnd,pos);
_LIT8(KData,"Hi");
fp.Write(KData);
fp.Close();
iFileServer.Close();
============================
Hope this would help u
Forum posts: 67
To complement the code already here, here is some very simple code to read the contents of a file into a heap-based descriptor.
I've put that code in the OpenFileL method of my document class (which explains where the parameters in the Open method come from).
  /* Txt file to be opened. */
  RFile file ;
  file.Open(aFs, aFilename,EFileRead) ;
  /* Size of file. */
  TInt iSize ; Â
  file.Size(iSize) ;
 Â
  /* Allocate enough memory to read in the whole file. */
  HBufC8* buf = HBufC8::NewLC(iSize) ;
  /* Get a pointer to modify contents of buffer. */
  TPtr8 pBuf = buf->Des() ;
  /* Read data into buf. */
  file.Read(pBuf) ;
  file.Close() ;
  /* When buf is not needed anymore... */
  CleanupStack::PopAndDestroy() ;
If we fall down it's so we can learn to pick ourselves up.
Forum posts: 2133
(Nikolas, don't forget to put your file on the CleanupStack just after opening it - CleanupClosePushL(file) - since the HBufC allocation may leave, and same for sree where the iFileServer should be on the cleanupstack - but it looks like this is just a data member of a class just copied in the example so this is probably ok anyway ).
Who can do this for the stream and store interfaces
Eric Bustarret
NewLC Founder & CEO / Professional Symbian OS Consultant
Forum posts: 1379
// 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);
I will do one for stores this avo if I get a spare minute, since it's a bit more involved.
didster
Forum posts: 1379
// 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);
}
didster
Forum posts: 1
hi,
I am trying to read and write Unicode data (16-bits) into file..... how i do it?
thanx in advance
Forum posts: 822
Use TFileText:
http://www.symbian.com/Developer/techlib/v70sdocs/doc_source/reference/cpp/FileServerClientSide/TFileTextClass.html
Or, just stream your descriptors to the stream:
TBuf<10> buf;// Put something to buf, have stream ready -- write to it
aStream << buf;
// The same with HBufC:
aStream << *myHBufC;
Or, if using RFile, copy the 16 bit descriptor data to a 8 bit descriptor and write it to the file:
TBuf8<20> my8BitBuf;my8BitBuf.Copy(a16BitBuf);
myFile.Write(my8BitBuf);