这个是基于AO实现的扫描引擎,使用timer来隔开每次AO,给点时间给进度条,保证显示流畅,如果性能要求高的话,建议使用多线程实现。
写 这个代码的时候,我对AO还一知半解,可能很多问题,大家自己review下。
这代码是比较完整的,功能是扫描指定路径,指定后缀的文件,并且添加到一个列表界面(列表如果需要的话,自己加把,这里只是一个传入参 数),并且显示进度条。
#include "ScanFolderEngine.h"
#define USE_TIMER_WHEN_SCANNING 1 // use timer to break some time to display progress bar
const TInt KFinalValue(100); //进度条最大值
const TInt KTimerStartDelay(1250000);//第一次开始任务的延迟,主要是给时间给progress的显示
const TInt KTimerInterval(0);//计时器的间隔
const TInt KIncrement(5); //进度条每次增长的值(或者减小)
_LIT(KFormatXxx, ".xxx");
_LIT(KFormatYyy, ".yyy");
_LIT(KFormatZzz, ".zzz");
CScanFolderEngine * CScanFolderEngine::NewLC( CUIListContainer *pUIListContainer )
{
CScanFolderEngine* self = new (ELeave) CScanFolderEngine(pUIListContainer);
CleanupStack::PushL(self);
self->ConstructL();
return self;
}
CScanFolderEngine * CScanFolderEngine::NewL( CUIListContainer *pUIListContainer )
{
CScanFolderEngine* self = CScanFolderEngine::NewLC(pUIListContainer);
CleanupStack::Pop(self);
return self;
}
CScanFolderEngine::CScanFolderEngine(CUIListContainer *pUIListContainer)
: CActive(0)
, iErrorFlag(EFalse)
, iDestroyFlag(EFalse)
, m_pUIListContainer(pUIListContainer)
, m_bFinished(EFalse)
, m_nErrCount(0)
{
}
void CScanFolderEngine::ConstructL()
{
m_nIncreaseDir = 0;
#ifdef USE_TIMER_WHEN_SCANNING
iTimer.CreateLocal();
#endif // USE_TIMER_WHEN_SCANNING
CActiveScheduler::Add(this);
User::LeaveIfError(iFs.Connect());
}
CScanFolderEngine::~CScanFolderEngine()
{
#ifndef USE_TIMER_WHEN_SCANNING
if(iStatus == KRequestPending)
{
TRequestStatus* status = &iStatus;
User::RequestComplete( status, KErrCancel);
}
Cancel();
#else
Cancel();
iTimer.Close();
#endif // USE_TIMER_WHEN_SCANNING
if(iProgressDialog) {
delete iProgressDialog;
iProgressDialog = 0;
}
iFs.Close();
}
/**
* @brief 真正的扫描逻辑
*/
void CScanFolderEngine::DoScan()
{
#ifdef USE_TIMER_WHEN_SCANNING
TInt delay = KTimerInterval;
iTimer.After(iStatus, delay);
#endif // USE_TIMER_WHEN_SCANNING
if(m_DirStack.Count() == 0) {
m_bFinished = ETrue;
return;
}
HBufC *buf = m_DirStack[m_DirStack.Count()-1];
char *ansi_filename = new char[KMaxFileName*2+1]; // unicode
TInt src_len = buf->Des().Length();
TInt convert_len = 0;
convert_len = PubFunction::U2A_char((const wchar_t*)buf->Des().Ptr(), src_len, ansi_filename);
ansi_filename[convert_len] = 0;
string sPath = string(ansi_filename, convert_len); // bug 0027128
delete ansi_filename;
TBool bResult = ETrue;
if(m_Mark.find(sPath) != m_Mark.end()) { // 已经访问过,从上次位置开始
// 访问目录
CDir* dirs = NULL;
CDir *files = NULL;
TInt nErr = iFs.GetDir(buf->Des(), KEntryAttNormal, ESortByName, files, dirs);
if(nErr != KErrNone) { // 这个文件夹访问出错
delete m_DirStack[m_DirStack.Count()-1];
m_DirStack.Remove(m_DirStack.Count()-1);
} else {
CleanupStack::PushL(dirs);
CleanupStack::PushL(files);
TInt numberDirs = dirs->Count();
//TraceLog("numberDirs %d/n", numberDirs);
if(numberDirs <= m_Mark[sPath]) { // 已经访问完了,把当前目录出栈
delete m_DirStack[m_DirStack.Count()-1];
m_DirStack.Remove(m_DirStack.Count()-1);
IncreaseProgress();
} else { // 访问下一个目录
// 添加要访问的目录
if(m_DirStack.Count() >= STACK_DEPTH) {
bResult = EFalse;
m_nFinishReason = EFinishStackFull;
} else {
TBuf<KMaxPath> sBuf;
sBuf.Append(buf->Des());
sBuf.Append((*dirs)[m_Mark[sPath]].iName);
sBuf.Append(_L("//")); // - 这里要用//结尾,不然就当是文件
m_DirStack.Append(sBuf.Alloc());
m_Mark[sPath] ++;
m_nFolderScanned ++;
}
}
CleanupStack::PopAndDestroy(files);
CleanupStack::PopAndDestroy(dirs);
}
} else { // 未访问过,遍历文件与文件夹
//TraceLog("new sPath %s/n", sPath.c_str());
m_Mark[sPath] = 0;
//TraceLog("test find %d %d/n", m_Mark.find(sPath) == m_Mark.end(), m_Mark[sPath]);
CDir* dirs = NULL;
CDir *files = NULL;
//if(!buf->Compare(_L("e://PRIVATE//"))) { // TODO: 这里可以注释掉了
// TraceLog("this is PRIVATE dir!!");
//}
#ifdef __TUI_SUPPORTED__
if(!buf->Compare(_L("c://resource//"))) {
TraceLog("this is 5th c://resource// dir!!/n");
delete m_DirStack[m_DirStack.Count()-1];
m_DirStack.Remove(m_DirStack.Count()-1);
} else {
#endif // __TUI_SUPPORTED__
TInt nErr = iFs.GetDir(buf->Des(), KEntryAttNormal, ESortByName, files, dirs);
if(nErr != KErrNone) { // 这个文件夹访问出错
//TraceLog(L"dir access error1 %s dir: %s/n", (TInt)nErr, buf->Des().Ptr());
delete m_DirStack[m_DirStack.Count()-1];
m_DirStack.Remove(m_DirStack.Count()-1);
} else {
CleanupStack::PushL(dirs);
CleanupStack::PushL(files);
//TraceLog("CScanFolderEngine start add files from " << buf->Des());
TInt numberDirs = dirs->Count();
TInt numberFiles = files->Count();
//TraceLog("numberFiles %d/n", numberFiles);
for(TInt a = 0; a < numberFiles; a++)
{
TraceLog("check file %d/n", a);
const TEntry& file = (*files)[a];
IncreaseProgress(); // 对于文件访问现在也会增加进度
//TPtrC tptrRight = file.iName.Right(4);
TBuf<KMaxPath> tbufLowerCase;
//file.iName.Copy(tbufLowerCase, KMaxPath);
tbufLowerCase.Append(file.iName.Ptr(), file.iName.Length());
tbufLowerCase.LowerCase();
TPtrC tptrRight = tbufLowerCase.Right(4);
if(tptrRight.Compare(KFormatXxx()) && tptrRight.Compare(KFormatYyy()) && tptrRight.Compare(KFormatZzz())) {
continue;
}
//TraceLog("add file " << file.iName);
// 添加到列表
//HBufC *sFilePath = file.iName.Alloc();
//CleanupStack::PushL(sFilePath);
TBuf<KMaxPath> sBuf;
sBuf.Append(buf->Des());
sBuf.Append(file.iName);
HBufC *hTmp = sBuf.Alloc();
CleanupStack::PushL(hTmp);
StringW_t strFilePath = StringW_t(*hTmp);
//StringW_t strFilePath = StringW_t(*sFilePath);
m_pUIListContainer->DoAddItem(strFilePath, EFalse); // 添加,但是先不写ini
CleanupStack::PopAndDestroy(hTmp);
//CleanupStack::PopAndDestroy(sFilePath);
m_nFileAdded ++;
}
if(numberDirs) {
// 添加第一个dir
if(m_DirStack.Count() >= STACK_DEPTH) {
bResult = EFalse;
m_nFinishReason = EFinishStackFull;
} else {
TBuf<KMaxPath> sBuf;
sBuf.Append(buf->Des());
/// sBuf.Append(_L("//")); - 列出的目录一定是//结尾的,这里不需要加了。
sBuf.Append((*dirs)[0].iName);
sBuf.Append(_L("//")); // - 这里要用//结尾,不然就当是文件
m_DirStack.Append(sBuf.Alloc());
m_Mark[sPath] ++;
m_nFolderScanned ++;
}
} else { // 该目录没有子目录,出栈
delete m_DirStack[m_DirStack.Count()-1];
m_DirStack.Remove(m_DirStack.Count()-1);
IncreaseProgress();
}
CleanupStack::PopAndDestroy(files);
CleanupStack::PopAndDestroy(dirs);
} // end if access err
#ifdef __TUI_SUPPORTED__
} // end if skip
#endif // __TUI_SUPPORTED__
}
if(bResult == EFalse) {
m_bFinished = ETrue;
}
}
/**
* @brief 扫描文件夹下的文件
*/
void CScanFolderEngine::ScanFolderL( const TDesC &aRootPath )
{
TraceLog("ScanFolder==========================================/n");
// 初始化
m_bFinished = EFalse;
m_nFileAdded = 0;
m_nFileScanned = 0;
m_nFolderScanned = 0;
iDestroyFlag = EFalse;
iErrorFlag = EFalse;
m_nFinishReason = EFinishSucc;
m_nProgressNum = 0;
m_nErrCount = 0;
if(m_DirStack.Count()) {
for(int i=0;i<m_DirStack.Count();++i) {
delete m_DirStack[i];
}
m_DirStack.Reset();
} // TODO: 确定reset就释放了所有内存
HBufC *bufPath = aRootPath.Alloc(); // TODO: 错误处理
m_DirStack.Append(bufPath);
m_Mark.clear();
m_nIncreaseDir = 0;
iProgressDialog = new (ELeave) CAknProgressDialog (reinterpret_cast<CEikDialog**>(&iProgressDialog)); //创建进度条框对象
#ifdef SDK_S60_3RD
iProgressDialog->PrepareLC(R_PROGRESSNOTE_ADDING_FOLDER_NOTE_3RD);// 从资源中加载界面
#else
iProgressDialog->PrepareLC(R_PROGRESSNOTE_ADDING_FOLDER_NOTE);// 从资源中加载界面
#endif // SDK_S60_3RD
iProgressDialog->SetCallback (this); // calls DialogDismissL on completion
CEikProgressInfo* progressBar = iProgressDialog->GetProgressInfoL(); // not taking ownership
progressBar->SetFinalValue(KFinalValue); // Set final value of progress bar
iProgressDialog->RunLD(); // this doesn't actually delete the dialog despite the 'D' suffix
//DoScan(); // make a synchronous request
IncreaseProgress();
#ifdef USE_TIMER_WHEN_SCANNING
iTimer.After(iStatus, KTimerStartDelay);
SetActive(); // set the active object to be active
#else
SetActive();
TRequestStatus* status = &iStatus;
User::RequestComplete( status, KErrNone );
#endif // USE_TIMER_WHEN_SCANNING
}
/**
* @brief 这里继续做文件夹扫描工作
*/
void CScanFolderEngine::RunL()
{
TraceLog("RunL/n");
if((iStatus == KErrNone) && !iDestroyFlag && !iErrorFlag) {
TraceLog("iStatus ok/n");
if (!IsProcessDone())
{
TraceLog("!IsProcessDone()/n");
DoScan();
//IncreaseProgress();
SetActive(); // do scan里面会SetActive
#ifndef USE_TIMER_WHEN_SCANNING
TRequestStatus* status = &iStatus;
User::RequestComplete( status, KErrNone );
#endif // USE_TIMER_WHEN_SCANNING
}
else
{
TraceLog("IsProcessDone/n");
iProgressDialog->SetCallback(0);
iProgressDialog->ProcessFinishedL();
Final();
}
} else {
TraceLog("not ok iStatus %d iDestroyFlag %d iErrorFlag %d/n", (int)iStatus.Int(), (int)iDestroyFlag, (int)iErrorFlag);
}
// 上次已经在Final里面设置destroy
if(iDestroyFlag)
{
// 除非实在ExecuteLD里面运行这个AO才进行自我delete
//if(iWait)
// CAknEnv::StopSchedulerWaitWithBusyMessage(*iWait);
//else
// delete this;
}
}
/**
* @brief 如果RunL Leave了就 call该函数
*/
TInt CScanFolderEngine::RunError(TInt aError)
{
TraceLog("RunError() %d/n", aError);
iErrorFlag = ETrue;
// since RunError() function may not leave we must trap
TRAPD(error, iProgressDialog->ProcessFinishedL());
if(error != KErrNone) {
Final();
HBufC* noteText;
noteText = StringLoader::LoadLC(R_PROJECT_SOFTWARE_EXCEPTION);
CAknErrorNote* note = new(ELeave)CAknErrorNote();
note->ExecuteLD(*noteText);
CleanupStack::PopAndDestroy(noteText);
}
return KErrNone; // 表示已经处理了。
//return aError;
}
/**
* @brief 取消文件夹扫描
*/
void CScanFolderEngine::DoCancel()
{
TraceLog("DoCancel()/n");
iTimer.Cancel();
}
/**
* @brief 结束,保证再call一次RunL()
* Since it is possible that this function is called when the class CProgressProcessor instance as active object is either active or inactive, it is necessary to ensure that function RunL() will be called once more.
*/
void CScanFolderEngine::Final()
{
TraceLog("Final()/n");
iDestroyFlag = ETrue;
if(!IsActive())
{
#ifdef USE_TIMER_WHEN_SCANNING
iTimer.After(iStatus,0);
SetActive();
#else
SetActive();
TRequestStatus* status = &iStatus;
User::RequestComplete( status, KErrNone );
#endif // USE_TIMER_WHEN_SCANNING
}
else {
#ifdef USE_TIMER_WHEN_SCANNING
iTimer.Cancel();
#endif // USE_TIMER_WHEN_SCANNING
}
CleanUpProgress();
}
/**
* @brief 进度条取消的callback
*/
void CScanFolderEngine::DialogDismissedL(TInt aButtonId)
{
TraceLog("DialogDismissedL()/n");
m_nFinishReason = EFinishUserCancel;
if (!IsProcessDone())
{
CancelProgress();
}
else
{
CleanUpProgress();
}
//m_bFinished = EFalse;
m_nFileAdded = 0;
m_nFileScanned = 0;
m_nFolderScanned = 0;
}
/**
* @brief 判断是否完成了扫描的处理
*/
TBool CScanFolderEngine::IsProcessDone() const
{
//return m_nFolderScanned == 10;
return m_bFinished;
}
/**
* @brief 取消扫描文件夹
*/
void CScanFolderEngine::CancelProgress()
{
TraceLog("CancelProgress()/n");
Cancel();
CleanUpProgress();
}
/**
* @brief 取消或者正常完成扫描后的清除工作
*/
void CScanFolderEngine::CleanUpProgress()
{
TraceLog("CleanUpProgress()/n");
if(m_DirStack.Count()) {
for(int i=0;i<m_DirStack.Count();++i) {
delete m_DirStack[i];
}
m_DirStack.Reset();
}
// 写ini
m_pUIListContainer->OnFinishScan(m_nFinishReason);
}
void CScanFolderEngine::IncreaseProgress()
{
if(m_nIncreaseDir == 0) {
if(m_nProgressNum + KIncrement <= 100) {
m_nProgressNum += KIncrement;
iProgressDialog->GetProgressInfoL()->SetAndDraw(m_nProgressNum);
} else {
m_nIncreaseDir = 1;
}
} else {
if(m_nProgressNum - KIncrement >= 0) {
m_nProgressNum -= KIncrement;
iProgressDialog->GetProgressInfoL()->SetAndDraw(m_nProgressNum);
} else {
m_nIncreaseDir = 0;
}
}
/*
if(m_nProgressNum < 99) {
iProgressDialog->GetProgressInfoL()->IncrementAndDraw(KIncrement); // increment the progress bar
m_nProgressNum += KIncrement;
}*/
}
#endif // USE_MINI_CORE