TFileName KMaxFileName=256。因为太耗费资源,建议大家尽量不使用。"/>
技术开发 频道

详解Symbian 中的文件操作

  【IT168技术】Symbian提供了文件服务器(RFile)和文件会话(RFs)来支持文件操作。可以像PC一样,Symbian也支持长文件名,但是不支持"."和".."。Symbian提供了一个TFileName类来表示文件名,其定义是:typedef TBuf <KMaxFileName>TFileName KMaxFileName=256。因为太耗费资源,建议大家尽量不使用。

  先说文件服务器。文件服务器提供了对目录和文件的管理功能。 与此相关的库和头文件是:efserv.lib 和 f32file.h,在项目中要进行手动的添加。先说目录,CDir类和TEntry类用来表示目录。CDir用于存放当前目录下的文件序列,类似一个数组。TEntry表示CDir里的每一个元素,通过CDir重载的下标操作符 [ ] 可以获得TEntry的对象。在使用文件服务器前,要创建一个RFs的服务器句柄对象 iFs,通过iFs的Connect( )方法与服务器建立文件会话。GetDir(const TDesC& aName, TUnit aEntryAttMask, TUnit aEntrySortKey, CDir* aEntryList ) const 获取当前目录的文件序列。参数所代表的意思可以根据参数的名字进行推测推。

  再说文件管理。文件管理是通过文件服务器来实现文件的读、写、删、建。在进行这么操作之前,首先要打开文件。如果要打开的文件存在,就可以通过RFile的Open(RFs aFs, const TDesC& aName, TUnit aFileMode)方法来实现,如果之前该文件不存在那么我们就可以通过Creat(RFs aFs, const TDesC& aName, TUnit aFileMode)方法来进行操作。不过通常建议使用Replace( RFs aFs, const TDesC& aName, TUnit aFileMode)方法,此方法的好处就在于当目标文件不存在时会自动创建,如果目标文件存在就会覆盖原文件。通过Write( )和Read( )可以实现文件的写和读。这两个函数都具有同步和异步两个版本,同步和异步的区别就在于参数TRequestStatus上。RFile的Create( )用于建立新文件,删除文件可以使用RFs的Delete( )。具体可以参考SDK Help。在使用完RFile和RFs之后应该Close( ),用来释放使用的服务器资源,这个不能忘记,否则会造成资源的浪费。

  在文件管理中有两个很重要的东西——流和存储。

  流可以方便的持续写入或者读取,相比文件存取操作的好处就在于文件读、写完后都要进行提交,也就是执行CommitL( ),执行一次读或者写就要提交一次会造成代码执行效率的下降,因此当数据较多时建议用流操作。Symbian里封装了两个流:RWriteStream是输出流的基类,RReadStream是输入流的基类。在此基础上派生出了文件输出/输入流:RFileWriteStream和RFileReadStream。在实例化文件输出流之后,调用Replace( )建立输出流(假定要写入的文件不存在),然后PushL( ),将此输出流压入清除栈。完成之后就可以向流写数据了。写完之后调用CommitL( )提交输出流的数据。之后调用RFileWriteStream的Pop( )和Release( ),这两句也等价于CleanupStack::PopAndDestory( ),通常情况下用的是后者,具有弹站和释放资源的双重作用。通过流向文件写数据的过程就是这样。通过流从文件读取数据的过程和写是差不多的。在向HBufC写数据的时候,可以通过HBufC的NewL(aStream, KMaxTInt )重载版本建立堆描述符,因为我们用到了流Stream,直接用流对象来构造堆描述符。

  Symbian的约定要求为任何可以外部化为流的对象提供一个可访问的公有的 ExternalozeL( ) 函数。这个函数以一个输出流的引用作为参数,其实就是将向流写数据的过程集中封装起来。同理,可以提供一个InternalizeL( )来读取数据。

  存储是多个流的集合。两个基于文件的存储是CDirectFileStore和CPermanentFileStore。后者允许写入后进行修改,而前者不行。在这里有一个Symbian特有的概念:流字典(stream dictionary)。它仅仅是另一个流,只不过它保存的是其他流ID和对应流UID之间的映射。可以像查字典一样,从流字典里找出需要的流。

  使用存储的大致方法是这样的:

  void CreateDirectFileStoreL( RFs& aFs, TDesC& aFileName, TUid aAppUid )

  {

  CFileStore* store = CDirectFileStore::ReplaceLC( aFs, aFileName, EFileWrite ); //创建Store

  store->SetTypeL( TUidType( KDirectFilestoreLayoutUid, KUidAppDllDoc, aAppUid ) ); //设置类型

  CStreamDictionary* dictionary = CStreamDictionary::NewLC( ); //建立流字典

  RStoreWriteStream stream; //写入流

  TStreamId id = stream.CreateLC( *store ); //获取流ID

  TInt16 i = 0x1234;

  stream<

  stream.CommitL( );  //写入

  CleanupStack::PopAndDestory( );

  dictionary->AssignL( aAppUid, id ); //在流字典中关联流ID

  RStoreWriteStream rootstream;

  TStreamId rootId = rootstream.CreateLC( *store );

  rootstream<<*dictionary;

  rootstream.CommitL( ); //根流

  CleanupStack::PopAndDestory( );

  store->SetRoot( rootId ); //设置根流ID

  store->CommitL( ); //存储

  CleanupStack::PopAndDestory( );

  }

  从存储中读取数据的方法就是将以上的过程反向:

  void ReadDirectFileStoreL( RFs& aFs, TDesC& aFileName, TUid aAppUid )

  {

  CFileStore* store = CDirectFileStore::OpenLC( aFs, aFileName, EFileRead ); //建立存储

  CStreamDictionary* dictionary = CStreamDictionary::NewLC( ); //建立流字典

  RStoreReadStream rootstream; //根流

  rootstream.OpenLC( *store, store->Root( ) ); //打开根流

  rootstream>>*dictionary; //写入流字典

  CleanupStack::PopAndDestory( );

  TStreamId id = dictionary->At( aAppUid ); //建立映射

  CleanupStack::PopAndDestory( );

  RStoreReadStream stream;

  stream.OpenLC( *store, id );

  TInt16 j;

  stream>>j; //读取数据

  CleanupStack::PopAndDestory( );

  CleanupStack::PopAndDestory( );

  }

0