Overview
In Symbian OS, there is several ways to write data on the file system :
using classical file interface
using streams and store
using the DBMS server
All the options could be suitable for our purpose. The file API is not that easy to use for writing arrays of C structure. The DBMS may be quite too complicated to the treatment we need to do. So I choose to use a Direct File Store. This is generally the best option when you want to manage your data in RAM memory (i.e. not inserting element directly on the file system).
The structure of a direct file store is as below:

The direct file store could contain several data stream, each of those could be accessed independently. However, once written, they cannot be modified nor deleted (you have to use a permanent file store if you need to do so). you can just delete the whole store.
Stream are easily read or written using << or >> operators. And are quite safe with the possibility to commit or rollback any changes if an error occurs.
Writing the TScore to a file store
The TScore class presented in Creation of a high score table (Part I): using a CArray has two new member functions: ExternalizeL() and InternalizeL():
class TScore
{
public :
TScore();
TScore(TInt aScore);
TScore(TInt aScore,const TDesC& aName);
TInt Score();
TInt Score(TPlayerName& aName);
void ExternalizeL(RWriteStream& aStream) const;
void InternalizeL(RReadStream& aStream);
TInt operator>(const TScore& aScore);
TInt operator<(const TScore& aScore);
TInt operator==(const TScore& aScore);
public :
TInt iValue;
private:
TPlayerName iName;
};
The ExternalizeL() function is responsible for writing a TScore structure to a file store:
void TScore::ExternalizeL(RWriteStream& aStream) const
{
//
// Write the score as a 32bit integer
// (You have to use a WriteXXX function since no << operator
// is available for integers)
//
aStream.WriteInt32L(iValue);
//
// Write the name
//
aStream << iName;
}
The InternalizeL() function reads a TScore from the store:
void TScore::InternalizeL(RReadStream& aStream)
{
//
// Read the score
//
iValue = aStream.ReadInt32L();
//
// Read the name
//
aStream >> iName;
}
Writing the whole CArray
The score table (iScoreTable) is owned by the CGame class which is then responsible for externalizing the whole array. The class definition in itself has not been really changed:
class CGame : public CBase
{
public :
static CGame *NewL();
static CGame *NewLC();
void ScoreDisplay();
void AddScoreL(const TScore& aScore);
void SaveScoreL(const TDesC& aStore);
void LoadScoreL(const TDesC& aStore);
void ResetScore();
~CGame();
private:
void ConstructL();
private:
CArrayFixSeg<TScore> *iScoreTable;
RFs iFs; // FileServer Session ID
};
It only has two new functions: SaveScoreL() and LoadScoreL() and a data member to hold a session id to the file server (iFs).
The connection to the file server is made in the CGame::ConstructL(). If the connection cannot been established, I decided to make the function leave since my (hypothetical) game would not run without it:
//
// Connect to the file server and create the directory if needed
//
User::LeaveIfError(iFs.Connect());
iFs.MkDirAll(KFileStore);
The MkDirAll() function will create any necessary directory that may be present in the path to my high score file (specified by KFileStore). This is probably useful for the first execution of my game but will have no action for the following ones.
The big work is made in the SaveScoreL() function and requires several steps:
create a full path name for the file, resolving any joker or default directory: this is done using TParse class and the Parse() call:
TParse parsedName;
iFs.Parse(aStoreName,parsedName);
create an empty file store (replacing the existibg one - if any) and open it in write mode (ReplaceLC()
CDirectFileStore::ReplaceLC(iFs,parsedName.FullName(),EFileWrite);
give it the type you want. Here, I choose Direct File Store because it is the simplest choice when you want to manage all the data in RAM memory rather than on the file system:
store->SetTypeL(KDirectFileStoreLayoutUid);
create the data stream inside the store:
RStoreWriteStream stream;
TStreamId id = stream.CreateLC(*store);
write all the data into the stream:
//
// Write the number of score table entries in the store
//
TInt count= iScoreTable->Count();
stream.WriteInt32L(count);
//
// Then write each entry
//
TInt i;
for(i=0;i<count;i++)
{
stream << iScoreTable->At(i); // This will call the TScore::ExternalizeL method
}
and finally commit the changes to the stream and to the store:
//
// Commit the changes to the stream
//
stream.CommitL();
CleanupStack::PopAndDestroy(); // stream id
//
// Set the stream in the store and commit the store
//
store->SetRootL(id);
store->CommitL();
CleanupStack::PopAndDestroy(); // store
The complete code in one shot:
void CGame::SaveScoreL(const TDesC& aStoreName)
{
//
// Create a direct file store that will contain the score table
// (Erase previous one)
//
TParse parsedName;
iFs.Parse(aStoreName,parsedName);
CFileStore* store = CDirectFileStore::ReplaceLC(iFs,parsedName.FullName(),EFileWrite);
store->SetTypeL(KDirectFileStoreLayoutUid);
//
// Create the hi-score stream
//
RStoreWriteStream stream;
TStreamId id = stream.CreateLC(*store);
//
// Write the number of score table entries in the store
//
TInt count= iScoreTable->Count();
stream.WriteInt32L(count);
//
// Then write each entry
//
TInt i;
for(i=0;i<count;i++)
{
stream << iScoreTable->At(i); // This will call the TScore::ExternalizeL method
}
//
// Commit the changes to the stream
//
stream.CommitL();
CleanupStack::PopAndDestroy(); // stream id
//
// Set the stream in the store and commit the store
//
store->SetRootL(id);
store->CommitL();
CleanupStack::PopAndDestroy(); // store
}

score2.zip
The TParse class is a little bit big to be allocated on the stack (in SaveScoreLand LoadScoreL). It would be better to allocate it on the heap this way:
parsedName=new(ELeave)TParse;
CleanupStack::PushL(parsedName);
..... function code....
CleanupStack::PopAndDestroy(); // parsedName
I know two methods :
you try to open your socre.dat file using Open(): if it returns KErrNotFound, the file does not exist and you can create it
U Can use BaflUtils::FileExists(). also
Meenu