字典流,是symbian中一个很好的存储解决方案。
你可以使用同一个文件存储大量不同类型,不同内容的信息,而不必理会他们存储的偏移量,也不用分成若干个小文件来存储(这样非常浪费存储空间)。
字典流提供了类似查字典的存取机制,你可以用一个id来查找一个字典里面的“词条”。这个词条可以是一个整数,一个字符串,甚至是一个列表,一个可序列化类的对象(实现了 void ExternalizeL(RWriteStream& aStream) const;和 void InternalizeL(RReadStream& aStream);的类的对象)。当你访问一个词条的时候不会影响到其他的词条。这就避免了传统流输入为了取出一个小小的变量而读出整个文件的缺点,也不必为每个小变量单独建个文件浪费大量的空间花费很多精力去维护。
字典流有一个根,这个根负责管理所有的词条。新建的“词条”对应的输出流的id必须AssignL到根流上。
使用字典流也很方便,就像使用字典一样,你拿着一个id去字典流里面读东西,字典流就给你你关心的内容。你写东西的时候字典流也不会乱写,而是按照你制定的id来写。
假如你的文件里面保存了3个id对应的数据段 依次是,A,B,C 如果B的大小发生了变化,保存B的时候,不会影响到A和C.只是把旧的B的内容冲掉了.b中的空间只跟最后一次写入B的大小有关系.
zhaotaobenny 有篇叫《Symbian的文件操作》文章http://www.sf.org.cn/Article/symbiandev/200701/19956.html
里面提供了一段关于字典流的代码。研究了一下发现里面有些问题,只能使用一个id存储,当我更换id而使用原来的文件名的时候,上一个id会被冲掉。
我研究后发现有两个地方需要改,一个试打开文件的方式要使用Open 如果失败了再replace
另外要先读出根流,把子流AssignL到根流上之后再保存。我改好后有把它封装成模版类这样用起来会更加方便。
// save and load object by using Dictionary StreamOperator
// windcao@peoplemail.com.cn
/**/ //
#if !defined(_DICTIONARYSTREAMOPERATOR_H__)
#define _DICTIONARYSTREAMOPERATOR_H__
#include < e32def.h >
#include < s32file.h > // link with estor.lib
template < typename T >
class CDictionaryStreamOperator
... {
public:
/**//**
* LoadL
* load object from stream,Leave KErrNotFound(-1)if fileNot exist or id not exist
* @param[out] aObj an object to be load
* @param[in] aID an uid of the dictionary session id
* @param[in] aFileName the filename of the dictionary store file
*/
static void LoadL(T& aObj,TUid aID,const TDesC& aFileName);
/**//**
* SaveL
* save object to stream
* @param[in] aObj the obj to be save
* @param[in] aID an uid of the dictionary session id
* @param[in] aFileName the filename of the dictionary store file
*/
static void SaveL(const T& aObj,TUid aID,const TDesC& aFileName);
} ;
template < typename T >
void CDictionaryStreamOperator < T > ::LoadL(T & aObj,TUid aID, const TDesC & aFileName)
... {
RFs fs;
User::LeaveIfError(fs.Connect());
CleanupClosePushL(fs);
CFileStore* store;
store = CDirectFileStore::OpenLC( fs, aFileName, EFileRead ); //建立存储
CStreamDictionary* dictionary = CStreamDictionary::NewLC( ); //建立流字典
RStoreReadStream rootstream; //根流
rootstream.OpenLC( *store, store->Root( ) ); //打开根流
rootstream>>*dictionary; //写入流字典
CleanupStack::PopAndDestroy( );
TStreamId id;
id = dictionary->At(aID);
CleanupStack::PopAndDestroy( );
RStoreReadStream stream;
stream.OpenLC( *store, id );
stream>>aObj;
CleanupStack::PopAndDestroy( );
CleanupStack::PopAndDestroy( );
CleanupStack::PopAndDestroy(); // fs
} ;
template < typename T >
void CDictionaryStreamOperator < T > ::SaveL( const T & aObj,TUid aID, const TDesC & aFileName)
... {
TInt pushCount=0;
RFs fs;
User::LeaveIfError(fs.Connect());
CleanupClosePushL(fs);
pushCount++;
CFileStore* store=NULL;
CStreamDictionary* dictionary = CStreamDictionary::NewLC( ); //创建流字典
pushCount++;
TRAPD(err,store= CDirectFileStore::OpenL( fs, aFileName, EFileWrite|EFileRead )); //打开或者创建Store
if(err==KErrNone)
...{
CleanupStack::PushL(store);
pushCount++;
store->SetTypeL( TUidType( KDirectFileStoreLayoutUid, KUidAppDllDoc, aID ) ); //设置类型
RStoreReadStream rootstreamIn;
rootstreamIn.OpenLC( *store ,store->Root()); //打开根流
rootstreamIn>>*dictionary; //读出根流
CleanupStack::PopAndDestroy();//rootstreamIn
}
else
...{
store=CDirectFileStore::ReplaceLC(fs, aFileName, EFileWrite );
pushCount++;
store->SetTypeL( TUidType( KDirectFileStoreLayoutUid, KUidAppDllDoc, aID ) ); //设置类型
}
RStoreWriteStream stream; //创建写入流
TStreamId id = stream.CreateLC( *store ); //获取流ID
stream<<aObj;
stream.CommitL( );
CleanupStack::PopAndDestroy( ); //写入对象
dictionary->AssignL( aID, id ); //在流字典中关联流ID
RStoreWriteStream rootstream;
TStreamId rootId = rootstream.CreateLC( *store );
rootstream<<*dictionary;
rootstream.CommitL( );
CleanupStack::PopAndDestroy( ); //写入根流
store->SetRootL( rootId ); //设置根流ID
store->CommitL( );
CleanupStack::PopAndDestroy(pushCount);
} ;
#endif // !defined(_DICTIONARYSTREAMOPERATOR_H__)