【C++】多线程全盘文件搜索
本帖最后由 Fluray 于 2014-5-5 08:23 编辑新建一个控制台,要支持MFC。
只用了MFC一个函数AfxBeginThread,其余的全是win API。线程函数修改自《windows程序设计 第2版》 王艳平 张铮 编著
// 多线程文件搜索.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <afxwin.h>
#include <process.h>
#include <iostream>
#include <stddef.h>
#define BUFSIZE 1024
using namespace std;
//int g_FileName=0;
struct CDirectoryNode : public CNoTrackObject
{
CDirectoryNode* pNext;// CTypedSimpleList类模板要使用此成员
char szDir; // 要查找的目录
};
class CRapidFinder
{
public:
CRapidFinder(int nMaxThread);
virtual ~CRapidFinder();
BOOL CheckFile(LPCTSTR lpszFileName);
int m_nResultCount; // 结果数目
int m_nThreadCount; // 活动线程数目
CTypedSimpleList<CDirectoryNode*> m_listDir; // 目录列表
CRITICAL_SECTION m_cs; // 关键代码段
const int m_nMaxThread; // 最大线程数目
char m_szMatchName; // 要搜索的文件
HANDLE m_hDirEvent; // 向m_listDir中添加新的目录后置位(受信)
HANDLE m_hExitEvent; // 各搜索线程将要退出时置位(受信)
};
// m_nMaxThread成员是一个const类型的变量,必须使用成员初始化列表来初始化它的值
CRapidFinder::CRapidFinder(int nMaxThread) : m_nMaxThread(nMaxThread)
{
m_nResultCount = 0;
m_nThreadCount = 0;
m_szMatchName = '\0';
m_listDir.Construct(offsetof(CDirectoryNode, pNext));
m_hDirEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
m_hExitEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
::InitializeCriticalSection(&m_cs);
}
CRapidFinder::~CRapidFinder()
{
::CloseHandle(m_hDirEvent);
::CloseHandle(m_hExitEvent);
::DeleteCriticalSection(&m_cs);
}
//包含此文件名的文件都会被查找到
//BOOL CRapidFinder::CheckFile(LPCTSTR lpszFileName)
//{
//char string;
//char strSearch;
//strcpy(string, lpszFileName);
//strcpy(strSearch, m_szMatchName);
//
//// 将字符串string和strSearch中的字符全部转化成大写
//_strupr(string);
//_strupr(strSearch);
//
//// 找出字符串strSearch在字符串string中第一次出现的位置
//// 如果string中不包含strSearch,strstr函数返回NULL
//if(strstr(string, strSearch) != NULL)
// return TRUE;
//
//return FALSE;
//}
//必须是相同问文件名(大小写可以不同)
BOOL CRapidFinder::CheckFile(LPCTSTR lpszFileName)
{
char string;
char strSearch;
strcpy(string, lpszFileName);
strcpy(strSearch, m_szMatchName);
// 将字符串string和strSearch中的字符全部转化成大写
_strupr(string);
_strupr(strSearch);
//如果两个文件名称相同
if(strcmp(string, strSearch) == 0)
return TRUE;
return FALSE;
}
UINT FinderEntry(LPVOID lpParam)
{
CRapidFinder* pFinder = (CRapidFinder*)lpParam;
CDirectoryNode* pNode = NULL; // 从m_listDir中取出的节点
BOOL bActive = TRUE; // 指示当前线程的状态
// 循环处理m_listDir列表中的目录
while(1)
{
// 从m_listDir列表中取出一个新的目录
::EnterCriticalSection(&pFinder->m_cs);
if(pFinder->m_listDir.IsEmpty())
{
bActive = FALSE;
}
else
{
pNode = pFinder->m_listDir.GetHead();
pFinder->m_listDir.Remove(pNode);
}
::LeaveCriticalSection(&pFinder->m_cs);
// m_listDir为空的话就试图在m_hDirEvent事件上等待
if(!bActive)
{
// 准备进入等待状态
::EnterCriticalSection(&pFinder->m_cs);
pFinder->m_nThreadCount--;
if(pFinder->m_nThreadCount == 0)// 查看是否已经查找完毕
{
::LeaveCriticalSection(&pFinder->m_cs);
break;
}
::LeaveCriticalSection(&pFinder->m_cs);
// 进入等待状态
ResetEvent(pFinder->m_hDirEvent);
::WaitForSingleObject(pFinder->m_hDirEvent, INFINITE);
// 变成活动线程后进入下一次循环
::EnterCriticalSection(&pFinder->m_cs);
pFinder->m_nThreadCount++;
::LeaveCriticalSection(&pFinder->m_cs);
bActive = TRUE;
continue;
}
// 在pNode指向的目录中查找文件
WIN32_FIND_DATA fileData;
HANDLE hFindFile;
// 设置成X:\XXXX\*.*的格式
if(pNode->szDir != '\\')
strcat(pNode->szDir, "\\");
strcat(pNode->szDir, "*.*");
hFindFile = ::FindFirstFile(pNode->szDir, &fileData);
if(hFindFile != INVALID_HANDLE_VALUE)
{
do
{
if(fileData.cFileName == '.')
continue;
if(fileData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
{
// 将搜索到的目录添加到目录列表中
// 为新的节点申请内存空间,设置完整的目录名称
CDirectoryNode* p = new CDirectoryNode;
strncpy(p->szDir, pNode->szDir, strlen(pNode->szDir)-3);
strcat(p->szDir, fileData.cFileName);
// 添加到列表中
::EnterCriticalSection(&pFinder->m_cs);
pFinder->m_listDir.AddHead(p);
::LeaveCriticalSection(&pFinder->m_cs);
// 促使一个“非活动线程”变成“活动线程”
::SetEvent(pFinder->m_hDirEvent);
}
else
{
// 检查搜索到的文件
if(pFinder->CheckFile(fileData.cFileName))
{
::EnterCriticalSection(&pFinder->m_cs);
::InterlockedIncrement((long*)&pFinder->m_nResultCount);
::LeaveCriticalSection(&pFinder->m_cs);
char FileName;
inti;
for (i=strlen(pNode->szDir)-4;i>=0;i--)
FileName=pNode->szDir;
FileName='\0';
strcat(FileName, fileData.cFileName);
printf("%s\n",FileName);
}
}
}while(::FindNextFile(hFindFile, &fileData));
}
// 此节点保存的目录已经搜索完毕,释放内存空间,进入下次循环
delete pNode;
pNode = NULL;
}
// 促使一个搜索线程从WaitForSingleObject函数返回,并退出循环
::SetEvent(pFinder->m_hDirEvent);
// 判断此线程是否是最后一个结束循环的线程,如果是就通知主线程
if(::WaitForSingleObject(pFinder->m_hDirEvent, 0) != WAIT_TIMEOUT)
// 如果此时pFinder->m_hDirEvent所对应的事件对象为受信状态,
// WaitForSingleObject函数的返回值将是WAIT_OBJECT_0
{
// 通知主线程最后一个搜索线程即将退出,文件搜索完毕
::SetEvent(pFinder->m_hExitEvent);
}
return 0;
}
void main()
{
char szFile;
char szPath ;
char szLogicalDriveStrings;
DWORD iLength;
int iSub;
int count=0;
clock_t start,end;//程序运行的起始和结束时间
float costtime;//程序耗时
printf("请输入想查找的文件名:");
scanf("%s",szFile);
ZeroMemory(szLogicalDriveStrings, BUFSIZE);
iLength = GetLogicalDriveStringsA(BUFSIZE-1, szLogicalDriveStrings);
start=clock();//开始计时
for(iSub=0; iSub<iLength; iSub+=4)
{
CRapidFinder* pFinder = new CRapidFinder(64);
CDirectoryNode* pNode = new CDirectoryNode;
//如果不是固定磁盘驱动器:本地硬盘或移动硬盘,忽略
if(GetDriveType(szLogicalDriveStrings+iSub)!=3)
continue;
/*printf("%s", szLogicalDriveStrings+iSub);*/
// 设置参数信息
strcpy(pNode->szDir, szLogicalDriveStrings+iSub);
pFinder->m_listDir.AddHead(pNode);
strcpy(pFinder->m_szMatchName, szFile);
// 创建辅助线程并等待查找结束
pFinder->m_nThreadCount = pFinder->m_nMaxThread;
for(int i=0; i<pFinder->m_nMaxThread; i++)
{
AfxBeginThread(FinderEntry, pFinder);
}
::WaitForSingleObject(pFinder->m_hExitEvent, INFINITE);
// 打印出结果
/*printf("%s 中最终查找到的文件的个数为:%d \n",szLogicalDriveStrings+iSub, pFinder->m_nResultCount);*/
count=count+pFinder->m_nResultCount;
delete pFinder;
}
end=clock();//计时结束
costtime= (float)(end - start) / CLOCKS_PER_SEC;//转换时间格式
/*ShellExecute(NULL,"open",g_FileName,NULL,NULL,SW_SHOWNORMAL);*/
printf("使用64个线程全盘搜索文件%s,一共搜索到%d个,用时%.5f s",szFile,count,costtime);
system("pause");
}
楼主 这个只支持 W7?还是通用?? 谢谢楼主分享 正好在写这方面的程序 感謝大大的分享 学习了 谢谢分享 感谢楼主分享
页:
[1]