Windows Practice_文件搜索器(四)_封装文件扫描器
来源:互联网 发布:mysql和oracle语法区别 编辑:程序博客网 时间:2024/05/20 01:43
类的封装
虽然前面几节实现了一个文件扫描器,但是总的来说都比较不好,因为我们无法对这些代码重用,所以我们要对文件扫描器进行封装。
但是一般的对于查找器的封装有两种查询方式,一种是阻塞的方式,另一种是非阻塞的方式,相信大家对这两种工作方式都已经很熟悉了。但是我还是要简单的介绍一下吧!
阻塞方式就是程序在执行这个函数的时候是被卡主的,直到所有的文件找完之后才退出;
非阻塞方式执行这个函数时候,会立即返回,然后调用next函数一个一个的去遍历,这两种方式各有优缺,视应用场景而定。
代码实现
首先来简单的看一下工程结构,如下图所示:
在Windows下进行开发的时候,一般会有一个command的一系列函数,比如获取系统中的内核数,这些方法我们没有办法把它们封装成一个类,但是可以使用一个类把它们装起来。
#ifndef _SYSTEM_H_#define _SYSTEM_H_//System.h#include <Windows.h>namespace PoEdu{ class CSystem { public: CSystem(); ~CSystem(); inline static unsigned GetSystemCPUNum() { if (!m_bInit) { GetSystemInfo(&m_systemInfo); m_bInit = TRUE; } return m_systemInfo.dwNumberOfProcessors; } private: static SYSTEM_INFO m_systemInfo; // 系统信息 static BOOL m_bInit; }; SYSTEM_INFO CSystem::m_systemInfo = { 0 }; BOOL CSystem::m_bInit = FALSE;}#endif//!_SYSTEM_H_
#ifndef _POEDUFILEFIND_H_#define _POEDUFILEFIND_H_#include <string>#include <vector>#include <Windows.h>//PoEduFileFind.h文件// 头文件包含顺序// C/C++// 系统// 自己的namespace PoEdu{ class CFileFinder { class CThread { public: typedef unsigned(__stdcall *ThreadFunc)(void *); CThread(ThreadFunc func, void *lParam) : m_func(func), m_lParam(lParam), m_hThread(INVALID_HANDLE_VALUE) { } ~CThread() { if (m_hThread != INVALID_HANDLE_VALUE) CloseHandle(m_hThread); } void Run(unsigned initFlag); private: ThreadFunc m_func; void *m_lParam; HANDLE m_hThread; }; public: CFileFinder(const std::wstring &wstrBeginDirName, const std::wstring &wstrSearch, const unsigned unMaxThreadNumber = 0, const std::wstring wstrFilter = L"*.*"); ~CFileFinder(); // 默认是不阻塞 // 阻塞时返回文件数量 // 非阻塞时返回0 unsigned Start(bool bBlock = false); // 返回下一个文件名(这是针对于非阻塞情况下的) BOOL GetNextSearchData(std::wstring &wstrNextData); // 返回所有找到的文件名(这是针对于阻塞情况下的) std::vector<std::wstring> GetAllGetSearchData(); std::wstring MakeStandardDir(std::wstring wstrDir); public: std::vector<std::wstring> m_vecDirNames; // 待扫描的文件夹名 private: const std::wstring m_wstrSearch; // 搜索对比的内容 unsigned int m_uMaxThreadNum; // 最大线程数 const std::wstring m_wstrFilter; // 过滤条件 std::vector<std::wstring> m_vecSearchResult; // 扫描到的所有文件名 HANDLE m_hHasFile; // 文件是否扫描完的时间内核对象句柄 HANDLE m_hGetFile; // 文件是否拿走 bool m_bHasnextFile; // 是否还有下一个文件 long m_lWaitThreadNum; HANDLE m_hExitEvent; HANDLE m_hPushDirEvent; std::vector<HANDLE> m_vecHandles; // 存放所有的线程句柄 CRITICAL_SECTION m_cs; // 类函数无法成为线程函数,它是类所有的 // 全局函数才能成为线程函数 // 全局函数才能成为线程函数 static unsigned __stdcall ThreadBegin(void *lParam); unsigned FuncBegin(); static unsigned __stdcall FindFileThreadFunc(void *lParam); };}#endif//!_POEDUFILEFIND_H_
//PoEduFileFind.cpp文件#include <process.h>#include "PoEduFileFind.h"#include "System.h"namespace PoEdu{ void CFileFinder::CThread::Run(unsigned initFlag) { m_hThread = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0, m_func, m_lParam, 0, nullptr)); } CFileFinder::CFileFinder(const std::wstring& wstrBeginDirName, const std::wstring& wstrSearch, const unsigned uMaxThreadNum, const std::wstring wstrFilter) : m_wstrSearch(wstrSearch), m_uMaxThreadNum(uMaxThreadNum == 0 ? PoEdu::CSystem::GetSystemCPUNum() * 2 : uMaxThreadNum), m_wstrFilter(wstrFilter), m_hHasFile(nullptr), m_hGetFile(nullptr), m_bHasnextFile(true), m_lWaitThreadNum(0), m_hExitEvent(nullptr), m_hPushDirEvent(nullptr) { m_vecDirNames.push_back(wstrBeginDirName); InitializeCriticalSection(&m_cs); } CFileFinder::~CFileFinder() { DeleteCriticalSection(&m_cs); for (auto handle : m_vecHandles) { CloseHandle(handle); } if (m_hHasFile) { CloseHandle(m_hHasFile); } if (m_hExitEvent) { CloseHandle(m_hExitEvent); } if (m_hPushDirEvent) { CloseHandle(m_hPushDirEvent); } } unsigned CFileFinder::Start(bool bBlock) { unsigned ret = 0; if (bBlock) { // 运行查找函数 ret = FuncBegin(); } else { // 启动线程运行查找函数 // 和外部的交互方式开始变得不一样了 m_hHasFile = CreateEvent(nullptr, TRUE, FALSE, nullptr); m_hGetFile = CreateEvent(nullptr, TRUE, FALSE, nullptr); CThread thread(ThreadBegin, this); thread.Run(0); ret = 0; } return ret; } BOOL CFileFinder::GetNextSearchData(std::wstring &wstrNextData) { SetEvent(m_hGetFile); BOOL ret = TRUE; if (m_lWaitThreadNum < (long)m_uMaxThreadNum) { WaitForSingleObject(m_hHasFile, INFINITE); wstrNextData = m_vecSearchResult.back(); ResetEvent(m_hHasFile); if (!m_bHasnextFile) { ret = FALSE; } } return ret; } std::vector<std::wstring> CFileFinder::GetAllGetSearchData() { std::vector<std::wstring> ret; return m_vecSearchResult; } std::wstring CFileFinder::MakeStandardDir(std::wstring wstrDir) { if (wstrDir.back() != L'\\') { wstrDir += L'\\'; } return wstrDir; } unsigned CFileFinder::ThreadBegin(void* lParam) { // 使用this指针需要考虑同步的问题 CFileFinder *pThis = (CFileFinder *)lParam; pThis->FuncBegin(); return 0; } unsigned CFileFinder::FuncBegin() { m_hExitEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr); m_hPushDirEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr); for (unsigned i = 0; i < m_uMaxThreadNum; ++i) { HANDLE handle = (HANDLE)_beginthreadex(nullptr, 0, FindFileThreadFunc, this, 0, nullptr); if (NULL == handle) { --i; } else { m_vecHandles.push_back(handle); } } // 等待线程查找完成 WaitForSingleObject(m_hExitEvent, INFINITE); return m_vecSearchResult.size(); } unsigned CFileFinder::FindFileThreadFunc(void* lParam) { CFileFinder *pThis = (CFileFinder *)lParam; std::wstring wstrSerach = pThis->m_wstrSearch; std::wstring wstrDirName; BOOL bRunnable = TRUE; while (true) { EnterCriticalSection(&(pThis->m_cs)); if (pThis->m_vecDirNames.empty()) { bRunnable = FALSE; } else { wstrDirName = pThis->m_vecDirNames.back(); pThis->m_vecDirNames.pop_back(); } LeaveCriticalSection(&(pThis->m_cs)); if (!bRunnable) { ResetEvent(pThis->m_hPushDirEvent); InterlockedAdd(&(pThis->m_lWaitThreadNum), 1); if (pThis->m_lWaitThreadNum == pThis->m_uMaxThreadNum) { SetEvent(pThis->m_hExitEvent); break; } WaitForSingleObject(pThis->m_hPushDirEvent, INFINITE); InterlockedAdd(&(pThis->m_lWaitThreadNum), -1); bRunnable = TRUE; continue; } // 扫描 WIN32_FIND_DATA find_data = { 0 }; HANDLE hFile = FindFirstFileW((pThis->MakeStandardDir(wstrDirName) + L"*.*").c_str(), &find_data); if (INVALID_HANDLE_VALUE != hFile) { do { if (wcscmp(find_data.cFileName, L".") == 0) { continue; } if (wcscmp(find_data.cFileName, L"..") == 0) { continue; } if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { EnterCriticalSection(&(pThis->m_cs)); pThis->m_vecDirNames.push_back(pThis->MakeStandardDir(wstrDirName) + find_data.cFileName); SetEvent(pThis->m_hPushDirEvent); LeaveCriticalSection(&(pThis->m_cs)); } else { if (wcsstr(find_data.cFileName, wstrSerach.c_str()) != nullptr) { EnterCriticalSection(&(pThis->m_cs)); std::wstring wstr = (pThis->MakeStandardDir(wstrDirName) + find_data.cFileName).c_str(); WaitForSingleObject(pThis->m_hGetFile, INFINITE); pThis->m_vecSearchResult.push_back(wstr); ResetEvent(pThis->m_hGetFile); SetEvent(pThis->m_hHasFile); LeaveCriticalSection(&(pThis->m_cs)); } } } while (FindNextFileW(hFile, &find_data)); if (!FindClose(hFile)) printf("error no:%d\r\n", errno); } } pThis->m_bHasnextFile = false; SetEvent(pThis->m_hHasFile); return pThis->m_vecDirNames.size(); }}
// main.cpp函数#include "PoEduFileFind.h"int main(){ printf("阻塞方式:\r\n"); PoEdu::CFileFinder fileFinder(L"C:", L"ntdll"); unsigned uFindSerchNum = fileFinder.Start(false); std::wstring wstrData; while (fileFinder.GetNextSearchData(wstrData)) { printf("%ls\r\n", wstrData.c_str()); } printf("\r\n\r\n非阻塞方式:\r\n"); PoEdu::CFileFinder fileFinder2(L"C:", L"ntdll"); uFindSerchNum = fileFinder2.Start(true); printf("共找到%d个与ntdll相关的文件\r\n", uFindSerchNum); std::vector<std::wstring> ret = fileFinder2.GetAllGetSearchData(); for (auto wstr : ret) { printf("%ls\r\n", wstr.c_str()); } system("pause"); return 0;}
运行结果如下:
文件扫描器的总结
即使我们使用多线程扫描,也达不到everything那样的扫描速度,这是为什么呢?难道everything使用了更厉害的多线程什么的吗?答案是否定的!因为扫描的原理不一样,我们自己实现的是每一次的搜索都是真真实实的搜索,而everything只有在一开始安装的时候会真正的去搜索,而以后的搜索会在数据库中搜索,它有一个后台服务线程在更新数据。
所以如果我们也使用一个数据库,那么扫描速度也会达到everything那样的速度的。
阅读全文
1 0
- Windows Practice_文件搜索器(四)_封装文件扫描器
- Windows Practice_文件搜索器(二)_多线程调试
- Windows Practice_文件搜索器(三)_线程池
- Windows Practice_文件_文件分割器(一)
- Windows Practice_文件_文件分割器(二)
- Windows Practice_文件_文件分割器(三)
- Windows Practice_文件搜索器(一)递归
- Windows Practice_文件_文件基础操作
- Windows Practice_文件_内存映射(一)
- Windows Practice_文件_注册表操作
- Windows Practice_闹钟(一)_简易记事本
- Windows Practice_闹钟(二)_简易记事本
- Windows Practice_闹钟(六)_控件对象
- Windows Practice_闹钟(四)_GDI对象概述
- Windows Practice_内存映射_加载BMP
- Windows Practice_闹钟(三)_作业讲解和GDI概述
- JAVA简易文件扫描器
- 20170816WindowsPrj01_01_文件扫描器
- HDU 6170 Two strings (二维DP)
- springmvc集成shiro后,session、request姓什么?
- python2/3---sort方法与sorted函数的使用
- Android 监听软键盘弹出
- Xor Sum Gym
- Windows Practice_文件搜索器(四)_封装文件扫描器
- Gym
- Codeforces 845 C Two TVs
- java lambda表达式
- Windows Practice_闹钟(一)_简易记事本
- 门面模式
- k-近邻算法
- $n$-Way Tie Gym
- python学习(一)之初探