文件读写方案确定:读写模式选择问题

devdiv帖子收藏

 

提问金额: 1 可用分

1.由于频繁写入文件,同时要读入该文件

很容易造成不同步的情况,,寻求大家解决 方案

要求如下:

1.RFileWriteStream时,该文件锁定,RFileReadStream只有等RFileWriteStream写完成之后才能读入
2.读文件是通过活动对象来检测写文件有变化,才开始读,如果该 文件锁定,需等待完成之后才能再读入

不知道该用哪种模式
  1. 读该文件:
  2. InternalizeSettingsDataL()
  3.     {
  4.     RFs& fs = iEikonEnv->FsSession();
  5.     RFileReadStream readStream;
  6.     TInt error = readStream.Open(fs, iSettingsFile, EFileRead);
  7.     TInt internalizationError = KErrNone;
  8.     // if file existed, try to read settings.
  9.     if (error == KErrNone)
  10.         {
  11.         TRAP(internalizationError, iData->LoadL(readStream);)
  12.                 }
  13.     readStream.Release();
  14.     // reading failed, settings file might be corrupted.   
  15.     if (internalizationError != KErrNone)
  16.         {
  17.         User::LeaveIfError(fs.Delete(iSettingsFile));
  18.         }
  19.     }
复制代码
写该 文件:
  1. ExternalizeSettingsDataL() const
  2. {
  3.         RFs& fs = iEikonEnv->FsSession();
  4.         RFileWriteStream writeStream;
  5.         TInt error = writeStream.Open(fs, iSettingsFile, EFileWrite);
  6.         // setting file did not exist, create one.
  7.         if (error != KErrNone)
  8.             {
  9. [b][b][color=Blue]//这里用EFileWrite|EFileShareExclusive 好像不行。。。。。。[/color][/b][/b]
  10.             User::LeaveIfError(writeStream.Create(fs, iSettingsFile, EFileWrite)); //
  11.             }
  12.         writeStream.PushL();
  13.         iData->SaveL(writeStream);
  14.         writeStream.CommitL();
  15.         writeStream.Pop();
  16.         writeStream.Release();
  17. }
  18. 记得其他语言都有写文件独占锁定的功能,,symbian的多的看的着痛。。。。。。。。。。。。。


    有经验的同学指点一二

回复:

如果是当进程可以使用RMutex达到你的要求,用一个C类包装文件的读写,
伪代码如下:
void ReadFileL(  )
{
iMutex.Wait();//iMutex是RMutex

//read file...

iReadStream.Close;//关闭文件

iMutex.Signal();
}

void WriteStreamL()
{
iMutex.Wait();//iMutex是RMutex

//write file...

iWriteStream.Close;//关闭文件

iMutex.Signal();
}

如果是多进程,则使用CS架构,将这C类放在Server端就行了.

如何使用RMutex

使用RMutex可以确保你的线程不会再同一时间试图改变同一个值。RMutex.Wait()提供一个锁机制,用RMutex.Signal()才能打开。

头文件

在线程间共享iShareValue变量

class CShared : CBase
    {
    public:
        static CShared* NewL();
        virtual ~CShared();
 
    private:
        CShared();
 
    public:
        RMutex      iMutex;
        // Shared data
        TInt        iSharedValue;
    };

源文件

生成一个线程,并将CShared数据指针传入:

// Create shared data
iSharedData = CShared::NewL();
 
// Create threads
iMyThread = CMyThread::NewL(*this);
iMyThread->SetShared(iSharedData);
 
iMyThread2 = CMyThread::NewL(*this);
iMyThread2->SetShared(iSharedData);

线程调用RMutex::Wait()开始睡眠等待

TInt CMyThread::ThreadFunction(TAny* aParams)
    {
    // Add cleanup stack support.
    CTrapCleanup* cleanupStack = CTrapCleanup::New();
 
    // Get pointer to thread host
    CMyThread* host = (CMyThread*)aParams;
 
    TRAPD(err,
        // Add support for active objects
        CActiveScheduler* activeScheduler = new (ELeave) CActiveScheduler;
        CleanupStack::PushL(activeScheduler);
        CActiveScheduler::Install(activeScheduler);
 
// Create and start CPeriodic class that is executed in this thread
        CPeriodic* periodic = CPeriodic::NewL(CActive::EPriorityLow);
        CleanupStack::PushL(periodic);
        periodic->Start(host->Interval(),host->Interval(),
        TCallBack(host->PeriodicTick, host));
 
// NOTE: When adding CActiveScheduler support for threads we have to
        // add at least one active object in it or it fails on
        // CActiveScheduler::Start().
        // CPeriodic is derived from CActive active object so that is good for
        // this example.
 
        // --> Thread execution starts
        CActiveScheduler::Start();
        // --> Thread execution ends (waiting for CActiveScheduler::Stop())
 
        CleanupStack::PopAndDestroy(periodic);
        CleanupStack::PopAndDestroy(activeScheduler);
        );
 
 
    host->ThreadExecuted(err);
    delete cleanupStack;
    return KErrNone;
    }

在睡眠后调用PeriodicTick()改变共享数据对象的值,并用RMutex::Signal()释放

TInt CMyThread::PeriodicTick(TAny* aObject)
    {
    CMyThread* mythread = (CMyThread*)aObject;
    if (mythread)
        {
        // ---> Acquire the lock
        mythread->Shared()->iMutex.Wait();
 
        // Change shared data value
        mythread->Shared()->iSharedValue++;
 
        // ---> Release the lock
        mythread->Shared()->iMutex.Signal();
 
        // Thread is executed once so time to stop it
        CActiveScheduler::Stop();
 
        // After this execution continues from CActiveScheduler::Start()
        }
    // Does not continue again
    // Note: Does not work with this CPeriodic class
    return EFalse;
    }

完成CShared数据

CShared* CShared::NewL()
    {
    CShared* self = new (ELeave) CShared();
    return self;
    }
CShared::CShared()
    {
    iMutex.CreateLocal();
    }
CShared::~CShared()
    {
    iMutex.Close();
    }

NOTE

 

线程依次去改变共享对象的值,如果调用RMutex::Wait()后另一个线程就要等待,在RMutex::Signal()之后才继续。

Retrieved from http://wiki.forum.nokia.com/index.php/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8RMutex

 

 

 

 

http://www.devdiv.net/thread-16357-1-1.html

文件服务器会话(File Server Session)

DevDiv Symbian技巧大全系列之文件服务器会话(File Server Session)

1、文件服务器会话(File Server Session)
    Symbian中的文件操作离不开文件服务器会话api——RFs。文件服务器运行于EFile.exe中,RFs api提供了通往文件服务器的“通道”,通过RFs我们可以执行各种文件操作。

2、获取File Server Session的常用方法

 

1)使用RFs的Connect()方法:
  1. RFs aFSSession;
  2. User::LeaveIfError(aFSSession.Connect());
  3. // 可以使用aFSSession
  4. // ......
  5. // 关闭file server session,释放相关资源
  6. aFSSession.Close();
2)使用CCoeEnv:
    GUI 程序拥有 控件 环境(CCoeEnv),CCoeEnv由app framework构造,它持有一个File Server Session,并提供一个FsSession()方法获取FSS:
  1. RFs& aFSSession = iCoeEnv->FsSession();
在UI框架中,CEikApplication、CCoeAppUi和CCoeControl都拥有iCoeEnv成员,所以在这些类中都可以使用上面的代码获取FSS。

3)使用CCoeEnv::Static():
    在GUI程序中,如果你想在一些自己写的一些类中获取FSS,可以使用下列方法:
  1. RFs& aFSSession = CCoeEnv::Static()->FsSession();
4)使用CEikonEnv:
    CEikonEnv继承自CCoeEnv,使用它来获取FSS与使用CCoeEnv是一样的。
  1. RFs& aFSSession = iEikonEnv->FsSession();
或者:
  1. RFs& aFSSession = CEikonEnv::Static()->FsSession();
说明:iEikonEnv 定义于eikdef.h中
  1. #define iEikonEnv (STATIC_CAST(CEikonEnv*,iCoeEnv))
常用文件操作
1、写入二进制数据

DevDiv Symbian技巧大全系列之常用文件操作

文件操作离不开RFile api,它提供了各种文件操作的接口,比如Read、Write、Seek等等
RFile提供了读写文件的接口,这些接口有各种不同的变种,但大体上分为2类:同步方法和异步方法。同步方法适用于小块数据操作;若数据量较大,应该使用异步方法来操作,一是节省内存,而是可以获得较好的UI体验。
    symbian中二进制数据通常存储在8位描述符中,如TBuf8、HBufC8。
    下面的函数演示了如何向一个文件写入二进制数据:
  1. static void WriteDesC8ToFileL(const TDesC& aFileName, const TDesC8& aBinaryData)
  2. {
  3.         RFile aFile;
  4.         User::LeaveIfError(aFile.Replace(CCoeEnv::Static()->FsSession(), aFileName, EFileWrite));
  5.         CleanupClosePushL(aFile);
  6.         User::LeaveIfError(aFile.Write(aBinaryData));
  7.         // It will be release the resource of file
  8.         // DO NOT Close AGAIN
  9.         CleanupStack::PopAndDestroy(&aFile);
  10. }、

  11. 2、读出二进制数据

本帖隐藏的内容需要回复才可以浏览

  1. static void ReadDesC8FromFileL(const TDesC& aFileName, TDes8& aBuffer)
  2. {
  3.         RFile aFile;
  4.         User::LeaveIfError(aFile.Open(CCoeEnv::Static()->FsSession(), aFileName, EFileRead));
  5.         CleanupClosePushL(aFile);
  6.        
  7.         User::LeaveIfError(aFile.Read(aBuffer));
  8.        
  9.         CleanupStack::PopAndDestroy(&aFile);
  10. }

  11. 3、从文本文件读取数据

本帖隐藏的内容需要回复才可以浏览

多行的文本文件一般都由EOL分隔符来分隔每一行的数据。Symbian中的分隔符是LF(0x0A)。
    Symbian的文本文件通常都保存为Unicode格式。读写文本文件的常用api是TFileText,由于文本文件通常都为Unicode,所以TFileText api使用16位描述符作为参数。下面的函数演示了如何读取一个文本文件:
  1. static void ReadTextFileL(const TDesC& aFileName, TDes& aBuffer)
  2. {
  3.         RFile aFile;
  4.         User::LeaveIfError(aFile.Open(CCoeEnv::Static()->FsSession(), aFileName, EFileRead | EFileStreamText));
  5.         CleanupClosePushL(aFile);
  6.        
  7.         // create a TFileText and points it to file
  8.         TFileText aFileText;
  9.         aFileText.Set(aFile);
  10.        
  11.         TBuf<256> buffer;
  12.        
  13.         TInt errCode = KErrNone;
  14.         while (errCode != KErrEof)
  15.         {
  16.                 errCode = aFileText.Read(buffer);
  17.                 if (errCode == KErrNone)
  18.                 {
  19.                         aBuffer.Append(buffer);
  20.                 }
  21.         }
  22.        
  23.         CleanupStack::PopAndDestroy(&aFile);
  24. }
使用TFileText可以读取换行符为CR LF(0x0D 0x0A)或LF(0x0A)的Unicode文件(包含BOM(Byte-Order Mark)的也可以)。另外注意不要使用TFileText来读取非Unicode文件,否则将会出现一些垃圾字符。



注意事项:

 

1、在Symbian OS V9之后(S60 3rd之后),系统中有一些目录是受保护的,读写这些目录必须具有相应的能力,比如向Resource目录写数据必须具有TCB能力才行。当你在文件操作是遇到-46错误,就要检查一下你所操作的目录是否需要特殊能力。
    2、使用RFile api时要特别关注api的返回值,它表示了文件操作是否正确完成,若发生错误,程序应该做一些错误处理。以下是一个简单的范例:
  1. _LIT16(KFileName, "C://Data//WantToWrite.ini");
  2. _LIT8(KWriteContent, "DevDiv Test");
  3.        
  4. TInt errCode = 0;
  5. TRAP(errCode, WriteDesC8ToFileL(KFileName, KWriteContent));
  6.        
  7. if (errCode == KErrPathNotFound)
  8. {
  9.         // 路径不存在,创建路径并重试
  10.         // 或者弹出错误提示告知用户,具体错误处理需根据需求或具体情况确定
  11. }

你可能感兴趣的:(thread,session,server,File,服务器,Symbian)