看流星社区

 找回密码
 注册账号
查看: 1990|回复: 0

运用多线程技术实现文件的快速搜索

[复制链接]

该用户从未签到

发表于 2013-5-16 09:00:34 | 显示全部楼层 |阅读模式
从一名初学者到如今一名熟练的VC程序员,得益于VC知识库的帮助,一直想着该如何回报。现撰此文,一来略表心意,二来和VC爱好者交流。

操作系统一般都提供了文件搜索的功能,但采用的是顺序搜索,搜索效率很底。而且按此法编程十分烦琐,在目录层次很多时,往往不好处理。本文采用多线程技术实现文件的快速搜索,代码量很少,执行效率极高。

其基本思想其实很简单,就是找到一个目录就开辟一个线程,文件的话当然在线程内就处理了。这样实现了同步搜索,速度当然快起来了。

本文程序运行效果图

以下介绍VC具体实现:

一、 搜索用到两个win32的两个函数:

HANDLE FindFirstFile(LPCTSTR lpFileName,LPWIN32_FIND_DATA lpFindFileData );
BOOL FindNextFile( HANDLE hFindFile, LPWIN32_FIND_DATA lpFindFileData );

二、 建立线程函数

首先要定义线程的参数结构用于文件信息的传递:

typedef struct tagTHREADPARAM {
        CString strPath;
        CString strFileName;
}THREADPARAM  m_param;

因为线程要操纵全局变量,所以定义互斥体:

CMutex m_mutexThreadCount,m_mutexThreadParam,m_mutexPath;

如果搜索完毕或搜索终止,要有事件通知,于是创建一个事件:

CEvent m_event(FALSE,FALSE,NULL,NULL);

UINT uThreadCount=0;//产生的线程数
CStringArray m_strPathArray;//存放搜索到的文件路径数组
//线程函数
UINT GetFilePathThreadProc(LPVOID pParam)
{
        if(pParam==NULL)
                AfxEndThread(NULL);       
        THREADPARAM * m_pParam=(THREADPARAM *)pParam;
        CString strPath=m_pParam->strPath;
        CString strFileName=m_pParam->strFileName;
        m_mutexThreadCount.Lock();
        uThreadCount++;
        m_mutexThreadCount.Unlock();
        HANDLE hFile;
        WIN32_FIND_DATA *pInfo=new WIN32_FIND_DATA;
        hFile = ::FindFirstFile(strPath+"\\*.*",pInfo);
        if(hFile==INVALID_HANDLE_VALUE)
        {
                delete pInfo;
                m_mutexThreadCount.Lock();
                uThreadCount--;
        //所有的线程完成,则激活事件,通知应用程序完成搜索(下同)
                if(uThreadCount==0)
                        m_event.SetEvent();
                m_mutexThreadCount.Unlock();
                return 0;
        }
        do{
                if(pInfo->cFileName[0]==''.'')
                        continue;
                char cFileName[MAX_PATH];
                strcpy(cFileName,pInfo->cFileName);
                CString strFile=cFileName;
                if(pInfo->dwFileAttributes==FILE_ATTRIBUTE_DIRECTORY)
                {
                    //如果是目录,则开辟新的搜索线程
                        m_mutexThreadParam.Lock();
                        m_param.strPath=strPath+"\\"+strFile;
                        m_param.strFileName=strFileName;
                        AfxBeginThread(GetFilePathThreadProc,&m_param, THREAD_PRIORITY_NORMAL);
                        m_mutexThreadParam.Unlock();               
                }
                else
                {
                        //如果是文件则直接与要搜索的文件比较
                        if(strFile==strFileName){
                                m_mutexPath.Lock();
                                m_strPathArray.Add(strPath+"\\"+strFile);
                                m_mutexPath.Unlock();
                                m_mutexThreadCount.Lock();
                                uThreadCount--;
                                if(uThreadCount==0)
                                        m_event.SetEvent();
                                m_mutexThreadCount.Unlock();       
                                return 0;
                        }
                }               
        }
        while(::FindNextFile( hFile,pInfo));
        ::FindClose(hFile);       
        delete pInfo;
        m_mutexThreadCount.Lock();
        uThreadCount--;
        if(uThreadCount==0)
                m_event.SetEvent();
        m_mutexThreadCount.Unlock();       
        return 0;
}

三、 调用线程函数执行搜索

void GetFilePath()
{
        m_event.ResetEvent();//将事件置为无信号状态
        uThreadCount=0;
        m_strPathArray.RemoveAll();       
        m_param.strPath=m_strPath;
        m_param.strFileName=m_strFileName;
        m_param.m_pListInfo=&m_ListInfo;
        //启动线程
        AfxBeginThread(GetFilePathThreadProc,&m_param, THREAD_PRIORITY_NORMAL);
        //等待搜索完成或终止事件的发生
        ::WaitForSingleObject(m_event.m_hObject,INFINITE);
        if(m_strPathArray.GetUpperBound()==-1){
                AfxMessageBox("没找到文件",MB_OK|MB_ICONINFORMATION);return;}
        for(int i=0;i

四、 如果想中途停止搜索,只需先将线程对象存放于一线程对象数组,当然每增加一个线程则添加一个线程对象到数组,每返回一个线程,则将该线程对象从数组中删除。这样在你想终止搜索时,可操作这些线程对象即可达到目的。具体调用两个函数:

BOOL GetExitCodeThread(HANDLE hThread,LPDWORD lpExitCode);
BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode);
BOOL GetExitCodeThread(
  HANDLE hThread,      // handle to the thread
  LPDWORD lpExitCode   // address to receive termination status
);
BOOL TerminateThread(
  HANDLE hThread,    // handle to thread
  DWORD dwExitCode   // exit code
);
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2024-4-29 11:47

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

快速回复 返回顶部 返回列表