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那样的速度的。

原创粉丝点击