文件查找之 模拟everything (一)
来源:互联网 发布:合肥市行知学校在哪 编辑:程序博客网 时间:2024/06/14 07:32
文件搜索是我们编码的时候经常遇到的问题,如何提高查找性能和效率是我们的目标,本文总结了我在实现文件查找性能提升时做的一些方法
常规实现: 递归查找 -- 通过传递根路径,递归查找
代码:
void MyFindFile(wstring strPath, wstring strFileName)
{
WIN32_FIND_DATA findData;
HANDLE hFile;
hFile = FindFirstFile((strPath + L"\\*.*").c_str(), &findData);
wstring wstrPathTmp;
do
{
if (!wcscmp(findData.cFileName, L".") || !wcscmp(findData.cFileName, L".."))
{
continue;
}
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
wstrPathTmp = strPath + L"\\" + findData.cFileName;
MyFindFile(wstrPathTmp.c_str(), strFileName);
}
if (wcsstr(findData.cFileName, strFileName.c_str()))
{
wcout << strPath + L"\\" + findData.cFileName << endl;
}
} while (FindNextFile(hFile, &findData));
}
尝试2:通过多线程提高性能,每次搜索如果查找到文件就进行目标匹配,否则就创建一个新的线程对新目标进行搜索,线程函数代码如下:
unsigned int __stdcall ThreadFun1(PVOID param){
pThreadInfo info = new ThreadInfo();
info = (pThreadInfo)param;
wstring strPath = info->strPath;
wstring strFindName = info->strFileName;
WIN32_FIND_DATA findData;
HANDLE hFile;
hFile = FindFirstFile((strPath + L"\\*.*").c_str(), &findData);
if (hFile == INVALID_HANDLE_VALUE)
{
//过滤掉没有权限或者其他原因不能范围的文件夹或者文件
g_TotalThreadNum--;
if (g_TotalThreadNum == 0)
{
SetEvent(g_event);
}
CloseHandle(hFile);
return 0;
}
wstring wstrPathTmp;
do
{
if (!wcscmp(findData.cFileName, L".") || !wcscmp(findData.cFileName, L".."))
{
continue;
}
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
g_TotalFolderNum++;
wstrPathTmp = strPath + L"\\" + findData.cFileName;
pThreadInfo param = new ThreadInfo();
param->strFileName = strFindName;
param->strPath = wstrPathTmp;
g_TotalThreadNum++;
HANDLE hThreadHandle = (HANDLE)_beginthreadex(NULL, 0, ThreadFun1, param, NULL, NULL);
CloseHandle(hThreadHandle);
}
else
{
g_TotalFileNum++;
if (wcsstr(findData.cFileName, strFindName.c_str()))
{
g_FindFileNum++;
wstring strFileInfo = strPath + L"\\" + findData.cFileName;
wcout << strFileInfo << endl;
}
}
} while (FindNextFile(hFile, &findData));
//释放申请的资源
delete param;
param = NULL;
g_TotalThreadNum--;
if (g_TotalThreadNum == 0)
{
SetEvent(g_event);
}
return 0;
}
但是我在主函数中想分析上述代码的性能,将执行的时间打印出来,发现退出事件g_event 不会有信号,经过多次调试发现这是一个“”坑“”代码,由于我搜索的是C盘整个目录
而我们的电脑硬件不能同时创建那么多个线程,会出现创建线程失败的情况,所以上述策略不好,而且我们在_beginthreadex 创建线程的时候一定要对返回值做判断。
尝试3: 创建指定个数的线程(一般的策略是 cpu核心数*2) ,这样就不会出现上面的问题
线程函数代码如下:
unsigned int __stdcall ThreadFun2(PVOID param)
{
while (true)
{
WaitForSingleObject(hGolobalEvent, INFINITE);
wstring strCurPath;
wstring srtCurName;
HANDLE hExitEvent = INVALID_HANDLE_VALUE;
int iCurThreadId = GetCurrentThreadId();
map<int, HANDLE>::iterator iter = hExitEvents.find(iCurThreadId);
if (iter != hExitEvents.end())
{
hExitEvent = iter->second;
}
EnterCriticalSection(&g_cs);
if (strTotalFolders.size() != 0)
{
pPoolThreadInfo tmpInfo = strTotalFolders.back();
strCurPath = tmpInfo->strFindPath;
srtCurName = tmpInfo->strFindFileName;
strTotalFolders.pop_back();
ResetEvent(hExitEvent);
}
else
{
ResetEvent(hGolobalEvent);
}
LeaveCriticalSection(&g_cs);
if (!strCurPath.empty())
{
WIN32_FIND_DATA findData;
HANDLE hFile;
hFile = FindFirstFile((strCurPath + L"\\*.*").c_str(), &findData);
if (hFile == INVALID_HANDLE_VALUE)
{
//过滤掉没有权限或者其他原因不能范围的文件夹或者文件
SetEvent(hExitEvent);
continue;
}
do
{
wstring wstrPathTmp;
if (!wcscmp(findData.cFileName, L".") || !wcscmp(findData.cFileName, L".."))
{
continue;
}
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
g_TotalFolderNum++;
wstrPathTmp = strCurPath + L"\\" + findData.cFileName;
pPoolThreadInfo newInfo = new PoolThreadInfo();
newInfo->strFilter = L"*.*";
newInfo->strFindPath = wstrPathTmp;
newInfo->strFindFileName = L"ntdll";
EnterCriticalSection(&g_cs);
strTotalFolders.push_back(newInfo);
LeaveCriticalSection(&g_cs);
SetEvent(hGolobalEvent);
}
else
{
g_TotalFileNum++;
if (wcsstr(findData.cFileName, srtCurName.c_str()))
{
g_FindFileNum++;
wstring strFileInfo = strCurPath + L"\\" + findData.cFileName;
EnterCriticalSection(&g_OutPutCs);
wcout << strFileInfo << endl;
LeaveCriticalSection(&g_OutPutCs);
}
}
} while (FindNextFile(hFile, &findData));
//本次搜索结束,发出退出信号
SetEvent(hExitEvent);
}
else
{
SetEvent(hExitEvent);
//ResetEvent(hGolobalEvent);
continue;
}
}
}
经过比较性能较递归性能一般情况下提高不少,但是相较于evertthing还是要慢,后面经过查资料,发现everthing的原理是提前搜索将数据存入数据库,后面的查找都是查找数据库操作,后面我会实现模拟everything;
下面我将编码过程中遇到的坑总结如下:
1: 要记得判断是否创建成功,尤其是在创建多个线程的情况下,这个是一个坑,当然其他的系统api也要注意同样的问题
2:记得释放句柄资源,释放new 创建的对象
3:做文件IO操作 或者其他访问的时候,要注意可能存在读取权限的问题,比如有些文件不让你读,拒绝访问
4:创建线程最好用_beginTreadex 不要使用createThread --这方面的论述比较多
5:要充分考虑线程同步访问的问题,使用STL的容器要考虑STL是多线程不安全的,还有cout输出也是要做多线程同步
- 文件查找之 模拟everything (一)
- everything文件快速查找
- everything块速查找文件
- Everything不错的文件查找工具
- 快速查找文件的工具Everything
- 文件查找工具Everything的使用技巧
- windows文件搜索软件之everything
- DO onething is everything 之android--handler总结(一)
- Everything研究之快速获取USN记录的文件路径
- Everything研究之快速获取USN记录的文件路径
- 文件搜索软件Everything
- everything搜索不到文件
- 数据结构之查找<一>
- 一段模拟按键查找文件的JS
- Linux 之文件查找
- Everything 秒杀文件搜索
- Windows: 文件搜索工具 -- Everything
- UVaLive 2995 Image Is Everything (贪心+模拟)
- windows storm 1.1.1启动失败解决
- MySQL集群搭建详解
- Spring容器中init Bean和destroy Bean的方式
- HDU 6152 Friend-Graph
- HDU6152 Friend-Graph(拉姆齐定理,2017中国大学生程序设计竞赛
- 文件查找之 模拟everything (一)
- B. Godsend(Round #429 (Div. 2))
- 如何用csdn的Markdown编辑器写博客
- JavaScript事件总结
- 设计模式——装饰模式
- call和apply的区别
- 使用Python对音频进行频谱分析
- 各编译工具说明
- python---把tab.py的tab键自动补齐命令脚本,放入包目录下,python所有文件都可以使用