Windows Practice_文件搜索器(四)_封装文件扫描器

类的封装

虽然前面几节实现了一个文件扫描器,但是总的来说都比较不好,因为我们无法对这些代码重用,所以我们要对文件扫描器进行封装。
但是一般的对于查找器的封装有两种查询方式,一种是阻塞的方式,另一种是非阻塞的方式,相信大家对这两种工作方式都已经很熟悉了。但是我还是要简单的介绍一下吧!
阻塞方式就是程序在执行这个函数的时候是被卡主的,直到所有的文件找完之后才退出;
非阻塞方式执行这个函数时候,会立即返回,然后调用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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值