首 页 | 新 闻 | Symbian | Android| Windows Mobile | J2ME | 下载中心 | 游戏策划招聘与求职 | 购书指南 | 视频教程
您现在的位置: 开发视界 >> Symbian英文资料 >> base >> 正文
Creation of a high score table (Part II): saving to a file store
作者:佚名    文章来源:不详    更新时间:2006-5-7 10:59:23

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

<<Creation of a high score table (Part I): using a CArray
Creation of a high score table (Part III): Display in a ListBox>>


相关文章:
How to reset the alternate makmake entry in Codewarrior
Carbide.vs - Disabling the MMP/PKG File update feature
Codewarrior: how to avoid the "Too Many Include Paths" error when using the UIQ 2.1 SDK
Carbide.c++: Setting up On Target Debugging
Display the extended panic code in Emulator or Device
Start automatically an application or an exe after its installation
Compress Your Symbian C++ Executables
How To Freeze New Exports From Dll
 

站点地图 | 加入收藏 | 联系站长 | 广告服务 |
QQ:280529124  Tel:0592-8271361 辽ICP备05021703号