Symbian学习--文件系统

来源:互联网 发布:睡眠记录的软件 编辑:程序博客网 时间:2024/06/08 02:26

(一)RFs

Symbian的文件操作是基于会话通信模式的,即用户需要手动连接服务器,生成会话句柄,并通过句柄向文件服务器发送一系列的文件操作请求,然后由服务器完成这些操作,并返回结果给客户端用户。而RFs就是这样一个句柄:

RFs FileSession;

FileSession.Connect();

……

FileSession.Close();

在Connect和Close之间,可以打开任意数目的文件或者目录,已经做任意次文件操作,但是在Close之前,请确保关闭基于这个会话打开的所有资源。

注意:打开文件服务器会话是开销较高的操作,因此GUI应用程序框架为我们提供了一个与框架生命周期几乎相同的长时间文件服务器会话。我们可以使用iCoeEnv->FsSession()访问它,因此在没有充分理由的情况下,请不要创建自己的会话,沿用GUI程序框架的这个会话即可。

另外,使用RFs需要#include ,并且在mmp文件中加上LIBRARY efsrv.lib。

RFs常用操作:

· MkDir()创建指定目录、MkDirAll()创建Path途径的所有目录如果它不存在的话、RmDir()删除目录、Rename()重命名目录或者文件、Delete()删除文件

使用MkDirAll时,C://FileService//one这样的路径无法创建出one那一级,必须使用这样的路径C://FileService//one//。

Rename有移动的效果,比如:旧目录为C://FileService//two//,新目录为C://two//,执行之后,two将被移动到和FileService同级的路径下,同时FileService中没有了two。

· NotifyChange()和NotifyChangeCancel()可以监听文件和目录变化(这两个函数应该是基于AO构建的,有空需要深入研究一下)

· ReadFileSection()可以在不打开文件的情况下查看文件数据

· PrivatePath()和CreatePrivatePath()为应用程序查询和创建私有路径

· SessionPath和SetSessionPath获取和设置RFs当前目录

RFs既可作为类的数据成员,也可以作为自动变量在栈上声明,以下是这两种情况的标准用法:

RFs作为数据成员:

Class MyClass

{

public:

~MyClass();

void functionL();

private:

RFs iFs;

}

void MyClass::functionL()

{

User::LeaveIfError(iFs.Connect());

}

MyClass::~MyClass()

{

iFs.Close();

}

RFs作为栈上的自动变量:

RFs fs;

User::LeaveIfError(fs.Connect());

CleanupStack::CleanupClosePushL(fs);

//some functions maybe leave

CleanupStack::PopAndDestroy();

注意:这里不用再执行fs.Close(),因为CleanupClosePushL是特殊的压清除栈函数,专门为R类设计,在PopAndDestroy时会自动Close掉R类资源。

(二)RDir

Symbian系统将目录操作设计为在RFs的子会话上进行,以减少打开会话的数目,减轻文件服务器负担。

因此,我们会看到RDir类打开时,直接执行Open函数并将RFs作为参数传入即可,无需Connect操作。

RFs fs;

RDir myDir;

myDir.Open(fs, dirName, KEntryAttNormal | KEntryAttDir);

(三)RFile

Symbian系统将文件操作设计为在RFs的子会话上进行,以减少打开会话的数目,减轻文件服务器负担。

_LIT(KFilePath, "C://file.txt");

_LIT8(KFileData, "HelloWorld");

RFs fs;

User::LeaveIfError(fs.Connect());

CleanupClosePushL(fs);

RFile file;

TInt err = file.Open(fs, KFilePath, EFileWrite);

if (KErrNotFound == err)

{

User::LeaveIfError(file.Create(fs, KFilePath, EFileWrite));

}

CleanupClosePushL(file);

//Write Operation

TInt pos = 0;

User::LeaveIfError(file.Seek(ESeekEnd, pos));

User::LeaveIfError(file.Write(KFileData));

//Read Operation

TBuf8<5> buf;

User::LeaveIfError(file.Seek(ESeekStart, pos));//Because pos is placed to the end while writing, so turn it to the beginning

User::LeaveIfError(file.Read(buf));

TBuf16<5> buf16;//Printf can not display TBuf8, so we convert it to TBuf16

buf16.Copy(buf);

console->Printf(buf16);

console->Printf(_L("/n"));

CleanupStack::PopAndDestroy();// Pop file

CleanupStack::PopAndDestroy();// Pop fs

除了Open和Create还有两种打开文件的方式,Replace()(删除现有文件并创建新的)和Temp()(打开临时文件并给它分配名称)。

Open和Create函数的第三个输入参数是一个TUint的数字,指示文件模式,我们可以通过将预设的enum TFileMode枚举值“或”起来,达到我们想要的几种文件模式的叠加。例如:EFileWrite是以写方式打开文件,EFileStream是以二进制模式打开,默认不设置就是二进制模式,如果想要以文本模式打开,则使用EFileStreamText即EFileWrite|EFileStreamText。以下是几个常用的枚举值:

· EFileRead:只读方式打开文件

· EFileWrite:可读可写方式打开文件,这个模式与EFileShareReadersOnly不匹配

· EFileStream:二进制方式打开文件,默认就是这种方式,因此无需在或中体现此值

· EFileStreamText:文本方式打开文件

· 其他共享访问的枚举值(主要就是控制多个程序读写同一文件的方式:共享或者互斥)

注意:

(1)上面例子中Seek是搜索文件的末尾,以便在最后插入数据。同时,RFile类的文件读写都是以8位为单位进行的,因此上例中的_LIT8(KFileData, "Helloworld"),如果被设置为_LIT(KFileData, " Helloworld ")在编译时将提示函数重载出错。

(2)上面的例子中执行一次Read就将buf全部填满,比如:文件中现在的内容是“Helloworld”10个字符,由于我们的buf长度只有5,因此,buf最终读取到的字符为“Hello”。这样看来,RFile不适合读取不定长度且没有分隔符的文件,因此,这种情况下我们推荐使用RFileStream来读写文件,因为RFileStream会自动在写文件时加入分隔符,读取时不用编程者做任何工作,就可以轻松读取文件内容。

(3)Open或者Create一个文件并进行一番操作之后,我们必须执行RFile的Close函数来关闭子会话,这里我们没有显示调用Close是因为PopAndDestroy帮我们做了个操作。

(四)流

Symbian中流的概念在两个基类中实现:RReadStream和RWriteStream,派生于他们的各种流支持与多种介质绑定:

· RFileReadStream和RFileWriteStream:与文件绑定

· RDesReadStream和RDesWriteStream、RMemReadStream和RMemWriteStream、RBufReadStream和RBufWriteStream:与内存绑定(应该是根据内存中对象不同选择使用三种中适合的一种,这个需要进一步研究)

· RStoreReadStream和RStoreWriteStream:流存储

· RDictionaryReadStream和RDictionaryWriteStream:字典存储

· REncryptStream和RDecryptStream:带加密功能的流

RFileReadStream和RFileWriteStream用法如下(直接将以下代码拷贝至console程序中的MainL函数即可执行):

_LIT(KFilePath, "C://file.txt");

_LIT(KHelloWorld, "HelloWorld");

_LIT(KWho, "I am Vincent");

_LIT(KBye, "GoodBye");

RFs fs;

User::LeaveIfError(fs.Connect());

CleanupClosePushL(fs);

//find the end of the file

RFile file;

TInt err = file.Open(fs, KFilePath, EFileWrite);

if ( err == KErrNotFound )

{

User::LeaveIfError(file.Create(fs, KFilePath, EFileWrite));

}

CleanupClosePushL(file);

TInt pos;

User::LeaveIfError(file.Size(pos));

//write operation

RFileWriteStream writer;

err = writer.Open(fs, KFilePath, EFileWrite);

if ( KErrNotFound == err )

{

User::LeaveIfError(writer.Create(fs, KFilePath, EFileWrite));

}

CleanupClosePushL(writer);

writer.Attach(file,pos);

writer<

writer<

writer<

CleanupStack::PopAndDestroy();// Pop writer

//read operation

TBuf<20> buf;

RFileReadStream reader;

User::LeaveIfError(reader.Open(fs, KFilePath, EFileRead));

CleanupClosePushL(reader);

reader >> buf;

console->Printf(buf);

console->Printf(_L("/n"));

reader >> buf;

console->Printf(buf);

console->Printf(_L("/n"));

reader >> buf;

console->Printf(buf);

console->Printf(_L("/n"));

CleanupStack::PopAndDestroy();// Pop reader

CleanupStack::PopAndDestroy();// Pop file

CleanupStack::PopAndDestroy();// Pop fs

注意:

(1)RFileWriteStream没有Seek位置的函数,因此利用RFile的Size找到末尾位置,再使用Attach进行末尾插入。

(2)使用CleanupClosePushL压入清除栈之后,使用PopAndDestroy操作弹出,实际上帮我们做了CommitL、Pop和Release的操作。因此,如果之前是使用writer.PushL入栈的话,我们就必须依次调用writer.CommitL()、writer.Pop()和writer.Release()。其中writer.CommitL()表示提交操作,如不执行,则不会真正写入文件。

原创粉丝点击