devdiv文章收藏
提問金額: 1 可用分
| 1.由於頻繁寫入檔案,同時要讀入該檔案 很容易造成不同步的情況,,尋求大家解決 方案 要求如下: 1.RFileWriteStream時,該檔案鎖定,RFileReadStream只有等RFileWriteStream寫完成之後才能讀入 2.讀檔案是通過使用中的物件來檢測寫檔案有變化,才開始讀,如果該 檔案鎖定,需等待完成之後才能再讀入 不知道該用哪種模式?
- 讀該檔案:
- InternalizeSettingsDataL()
- {
- RFs& fs = iEikonEnv->FsSession();
- RFileReadStream readStream;
- TInt error = readStream.Open(fs, iSettingsFile, EFileRead);
- TInt internalizationError = KErrNone;
- // if file existed, try to read settings.
- if (error == KErrNone)
- {
- TRAP(internalizationError, iData->LoadL(readStream);)
- }
- readStream.Release();
- // reading failed, settings file might be corrupted.
- if (internalizationError != KErrNone)
- {
- User::LeaveIfError(fs.Delete(iSettingsFile));
- }
- }
複製代碼 寫該 檔案:
- ExternalizeSettingsDataL() const
- {
- RFs& fs = iEikonEnv->FsSession();
- RFileWriteStream writeStream;
- TInt error = writeStream.Open(fs, iSettingsFile, EFileWrite);
- // setting file did not exist, create one.
- if (error != KErrNone)
- {
- [b][b][color=Blue]//這裡用EFileWrite|EFileShareExclusive 好像不行。。。。。。[/color][/b][/b]
- User::LeaveIfError(writeStream.Create(fs, iSettingsFile, EFileWrite)); //
- }
- writeStream.PushL();
- iData->SaveL(writeStream);
- writeStream.CommitL();
- writeStream.Pop();
- writeStream.Release();
- }
- 記得其他語言都有寫檔案獨佔鎖定的功能,,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()方法:
- RFs aFSSession;
- User::LeaveIfError(aFSSession.Connect());
- // 可以使用aFSSession
- // ......
- // 關閉file server session,釋放相關資源
- aFSSession.Close();
2)使用CCoeEnv: GUI程式擁有控制項環境(CCoeEnv),CCoeEnv由app framework構造,它持有一個File Server Session,並提供一個FsSession()方法擷取FSS:
- RFs& aFSSession = iCoeEnv->FsSession();
在UI架構中,CEikApplication、CCoeAppUi和CCoeControl都擁有iCoeEnv成員,所以在這些類中都可以使用上面的代碼擷取FSS。 3)使用CCoeEnv::Static(): 在GUI程式中,如果你想在一些自己寫的一些類中擷取FSS,可以使用下列方法:
- RFs& aFSSession = CCoeEnv::Static()->FsSession();
4)使用CEikonEnv: CEikonEnv繼承自CCoeEnv,使用它來擷取FSS與使用CCoeEnv是一樣的。
- RFs& aFSSession = iEikonEnv->FsSession();
或者:
- RFs& aFSSession = CEikonEnv::Static()->FsSession();
說明:iEikonEnv定義於eikdef.h中
- #define iEikonEnv (STATIC_CAST(CEikonEnv*,iCoeEnv))
熱門檔案操作 1、寫入位元據 DevDiv Symbian技巧大全系列之熱門檔案操作
| 檔案操作離不開RFile api,它提供了各種檔案操作的介面,比如Read、Write、Seek等等 |
RFile提供了讀寫檔案的介面,這些介面有各種不同的變種,但大體上分為2類:同步方法和非同步方法呼叫。同步方法適用於小塊資料操作;若資料量較大,應該使用非同步方法呼叫來操作,一是節省記憶體,而是可以獲得較好的UI體驗。 symbian中位元據通常儲存在8位描述符中,如TBuf8、HBufC8。 下面的函數示範了如何向一個檔案寫入位元據:
- static void WriteDesC8ToFileL(const TDesC& aFileName, const TDesC8& aBinaryData)
- {
- RFile aFile;
- User::LeaveIfError(aFile.Replace(CCoeEnv::Static()->FsSession(), aFileName, EFileWrite));
- CleanupClosePushL(aFile);
- User::LeaveIfError(aFile.Write(aBinaryData));
- // It will be release the resource of file
- // DO NOT Close AGAIN
- CleanupStack::PopAndDestroy(&aFile);
- }、
- 2、讀出位元據
本帖隱藏的內容需要回複才可以瀏覽
- static void ReadDesC8FromFileL(const TDesC& aFileName, TDes8& aBuffer)
- {
- RFile aFile;
- User::LeaveIfError(aFile.Open(CCoeEnv::Static()->FsSession(), aFileName, EFileRead));
- CleanupClosePushL(aFile);
-
- User::LeaveIfError(aFile.Read(aBuffer));
-
- CleanupStack::PopAndDestroy(&aFile);
- }
- 3、從文字檔讀取資料
本帖隱藏的內容需要回複才可以瀏覽多行的文字檔一般都由EOL分隔字元來分隔每一行的資料。Symbian中的分隔字元是LF(0x0A)。 Symbian的文字檔通常都儲存為Unicode格式。讀寫文字檔的常用api是TFileText,由於文字檔通常都為Unicode,所以TFileText api使用16位描述符作為參數。下面的函數示範了如何讀取一個文字檔:
- static void ReadTextFileL(const TDesC& aFileName, TDes& aBuffer)
- {
- RFile aFile;
- User::LeaveIfError(aFile.Open(CCoeEnv::Static()->FsSession(), aFileName, EFileRead | EFileStreamText));
- CleanupClosePushL(aFile);
-
- // create a TFileText and points it to file
- TFileText aFileText;
- aFileText.Set(aFile);
-
- TBuf<256> buffer;
-
- TInt errCode = KErrNone;
- while (errCode != KErrEof)
- {
- errCode = aFileText.Read(buffer);
- if (errCode == KErrNone)
- {
- aBuffer.Append(buffer);
- }
- }
-
- CleanupStack::PopAndDestroy(&aFile);
- }
使用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的傳回值,它表示了檔案操作是否正確完成,若發生錯誤,程式應該做一些錯誤處理。以下是一個簡單的範例:
- _LIT16(KFileName, "C://Data//WantToWrite.ini");
- _LIT8(KWriteContent, "DevDiv Test");
-
- TInt errCode = 0;
- TRAP(errCode, WriteDesC8ToFileL(KFileName, KWriteContent));
-
- if (errCode == KErrPathNotFound)
- {
- // 路徑不存在,建立路徑並重試
- // 或者彈出錯誤提示告知使用者,具體錯誤處理需根據需求或具體情況確定
- }
|