采用stack实现的文件夹循环深度优先遍历的基类

一般情况下,我们在遍历文件夹时,都采用递归方式,但在wince平台下测试发现,当递归深度达到46级时,出现stack overflow而导致程序崩溃。为了解决这个问题,将递归改进为循环,这样理论上可以做到无限,只要内存一直满足的前提下。下面的代码完整展现了Windows平台(含WinCE)下,改进的文件遍历算法——循环深度优先遍历。

头文件:

#ifndef CFILEFINDER_H_
#define CFILEFINDER_H_

#include <Windows.h>

#if 1
#include "hswstack.h"
#else
#include "hswqueue.h"
#endif


#ifndef FILE_STRING_STD
#define FILE_STRING_STD (260)
#endif

#ifndef CheckFilePath
#define CheckFilePathLength(x)  \
    if(wcslen(x) >= FILE_STRING_STD)\
    return 
#endif

#ifndef _TAG_FILE_FOLDER
#define _TAG_FILE_FOLDER

typedef struct tagFileFolder
{
    WCHAR wcName[FILE_STRING_STD];

    void operator()(LPCTSTR lpfile)
    {
        if (this)
        {
            CheckFilePathLength(lpfile);

            wcscpy_s(wcName,FILE_STRING_STD,lpfile);
        }
    }

    void operator=(const struct tagFileFolder _right)
    {
        if (this)
        {
            CheckFilePathLength(_right.wcName);
            wcscpy_s(wcName,FILE_STRING_STD,_right.wcName);
        }
    }
    bool operator==(LPCTSTR lpfile)const
    {
        if (this != NULL)
        {
            return !(wcsicmp(this->wcName,lpfile));
        }
    }
    bool operator==(const struct tagFileFolder _right)const
    {
        if (this != NULL)
        {
            return !(wcsicmp(this->wcName,_right.wcName));
        }
    }
    tagFileFolder()
    {
        memset(wcName,0,FILE_STRING_STD);
    }
    tagFileFolder(LPCTSTR lpfile)
    {
        CheckFilePathLength(lpfile);        
        wcscpy_s(wcName,FILE_STRING_STD,lpfile);
    }

}tFileItem,*PFileItem;//此结构体可以根据不同的应用场景来扩展。可以增加文件的扩展名,创建日期,修改日期,大小等,可以增加文件的属性
#endif

class CFileFinder//采用深度优先算法遍历文件夹及其子文件夹,不采用递归方式,采用循环方式
{
public:
    CFileFinder();
    virtual ~CFileFinder();

public:
    virtual BOOL Initialize() = 0;//初始化
    virtual void UnInitialize() = 0;//反初始化
    virtual BOOL UserFunction(LPCTSTR lpFolder, LPCTSTR lpFile) = 0;//遍历过程中,供派生类对象处理数据的接口
    virtual BOOL ScanOver() = 0;//扫描结束后,供派生类对象处理扫描出来的文件的接口

protected:
    virtual BOOL StartScan(LPCTSTR lpPath);
    virtual void StopScan();

protected:  
    CRITICAL_SECTION m_CS;  
    __forceinline void Lock()   {EnterCriticalSection(&m_CS);}
    __forceinline void Unlock() {LeaveCriticalSection(&m_CS);}
    virtual BOOL KillScanProc();
    virtual BOOL CreateScanProc();

private:    
    volatile BOOL m_bAbort;//控制当前是否扫描文件
    volatile BOOL m_bRunning;//控制扫描文件的线程退出与否
    HANDLE m_hEvtScan;
    HANDLE m_hThread;
    static DWORD WINAPI FileFindProc(LPVOID lp);
#if 1
    HswStack<tFileItem> m_list_folder;//用于存放文件夹的链表
#else
    HswQueue<tFileItem> m_list_folder;
#endif
    virtual BOOL ScanFiles();
};

#ifdef UNDER_CE
#include "ShlWapi.h"
#pragma comment(lib,"shlwapi.lib")
#else
#include <io.h>
#endif

#endif

源文件:

#include "FileFinder.h"

CFileFinder::CFileFinder()
{
    m_bRunning = FALSE; 
    m_hThread = NULL;
    m_hEvtScan = NULL;
    m_bAbort = FALSE;

    InitializeCriticalSection(&m_CS);
}

CFileFinder::~CFileFinder()
{
    StopScan();
    KillScanProc();
    m_list_folder.free();
    DeleteCriticalSection(&m_CS);
}

BOOL CFileFinder::StartScan(LPCTSTR lp)
{
    BOOL b = FALSE;

#ifdef UNDER_CE
    if (wcslen(lp) > 0 && PathFileExists(lp))
    {
#else
    WCHAR wPath[MAX_PATH];
    wsprintf(wPath,L"%s\\",lp);
    if(wcslen(lp) > 0 && (0 == _waccess(wPath,0)))
    {
#endif  
        InterlockedExchange((LONG*)&m_bRunning, (LONG)TRUE);

        InterlockedExchange((LONG*)&m_bAbort,(LONG)FALSE);

        Lock(); 

        m_list_folder.push(tFileItem(lp));  

        Unlock();

        SetEvent(m_hEvtScan);

        b = TRUE;
    }
    return b;
}

void CFileFinder::StopScan()
{
    InterlockedExchange((LONG*)&m_bAbort,TRUE);

    RETAILMSG(1,(L"%s,%d,.size %d\n",TEXT(__FUNCTION__),__LINE__,m_list_folder.size()));
}

BOOL CFileFinder::CreateScanProc()
{
    if (NULL == m_hThread)
    {
        m_bRunning = TRUE;
        m_bAbort = FALSE;
        m_hEvtScan = ::CreateEvent(NULL,FALSE,FALSE,NULL);
        m_hThread  = ::CreateThread(NULL,0,FileFindProc,this,0,NULL);

#ifdef UNDER_CE
        int iThread = ::CeGetThreadPriority(::GetCurrentThread());
        ::CeSetThreadPriority(m_hThread, iThread - 5);
#endif
    }
    return 1;
}

BOOL CFileFinder::KillScanProc()
{
    if (m_hThread)
    {
#ifdef UNDER_CE
        ::CeSetThreadPriority(m_hThread,CE_THREAD_PRIO_256_TIME_CRITICAL); 
#endif
        StopScan();
        InterlockedExchange((LONG*)&m_bRunning, (LONG)FALSE);
        WaitForSingleObject(m_hThread,INFINITE);
        CloseHandle(m_hThread);
        CloseHandle(m_hEvtScan);
        m_hThread = NULL;
        m_hEvtScan = NULL;
    }
    return TRUE;
}

DWORD CFileFinder::FileFindProc(LPVOID lp)
{
    CFileFinder *pThis = (CFileFinder*)lp;
    if (pThis != NULL)
    {
        DWORD dwWait;

        for (;pThis->m_bRunning;) 
        {
            dwWait = ::WaitForSingleObject(pThis->m_hEvtScan, 800);

            switch(dwWait)
            {
            case WAIT_OBJECT_0:
                {
                    pThis->Lock();  

                    DWORD dwTick = GetTickCount();  

                    BOOL ret = pThis->ScanFiles();//step1.扫描文件,并将文件存放在链表中

                    RETAILMSG(1,(L"scan time %d\n",GetTickCount()-dwTick));

                    if (ret)
                    {
                        //1、文件扫描完
                        pThis->ScanOver();
                    }
                    pThis->Unlock();
                }
                break;
            }
        }
    }
    return 56789;
}

BOOL CFileFinder::ScanFiles()
{   
    TCHAR   cs_temp_cur[FILE_STRING_STD];
    tFileItem folder;   
    WIN32_FIND_DATA filedata;
    BOOL bRet = TRUE;

    int itemp_folder_count = 0;
    int itemp_file_count = 0;

    while (!m_bAbort && m_list_folder.size() > 0 )
    {
        m_list_folder.pop(folder);//pop函数的实现方式直接决定了遍历的方式是深度优先遍历还是广度优先遍历
        //如果链表的push和pop操作都在链表的同一端,则类似栈操作,实现为深度优先遍历
        //如果链表的push和pop分别在链表的头和尾操作,则类型队列,实现为广度优先遍历

        wcscpy_s(cs_temp_cur, FILE_STRING_STD, folder.wcName);
        wcscat_s(cs_temp_cur, FILE_STRING_STD, L"\\*.*");

        HANDLE hFind = FindFirstFile(cs_temp_cur, &filedata);

        if (hFind != INVALID_HANDLE_VALUE) 
        {
            do 
            {
                if (filedata.cFileName[0] == L'.') 
                {
                    continue;
                }
                if (FILE_ATTRIBUTE_HIDDEN == (filedata.dwFileAttributes  & FILE_ATTRIBUTE_HIDDEN))
                {
                    continue;
                }
                wsprintf(cs_temp_cur,L"%s\\%s",folder.wcName,filedata.cFileName);
                wcscpy_s(filedata.cFileName,MAX_PATH,cs_temp_cur);

                if (FILE_ATTRIBUTE_DIRECTORY  == (filedata.dwFileAttributes  & FILE_ATTRIBUTE_DIRECTORY )) 
                {   
                    itemp_folder_count++;
                    m_list_folder.push(tFileItem(cs_temp_cur));
                }
                else
                {   itemp_file_count++;
                    UserFunction(folder.wcName,cs_temp_cur);}

                //Sleep(0);

            }while(!m_bAbort && FindNextFile(hFind, &filedata));

            FindClose(hFind);
        }
        //Sleep(0);
    }   
    int error = GetLastError();

    if (m_bAbort ||
        ((error != 18 && error != 0) || 4319 == error || 1609 == error || 3 == error || 1617 == error))
    {   
        bRet = FALSE;
    }
    m_list_folder.free();

    printf("total file count %d,,,,,total folder count %d\n",itemp_file_count,itemp_folder_count);
    return bRet;
}

hswstack.h文件可以在另一篇文章中找到。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值