Windows 实战项目 001 文件扫描器 (01)

Posted ☆﹎夜﹎☆

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Windows 实战项目 001 文件扫描器 (01)相关的知识,希望对你有一定的参考价值。

---恢复内容开始---

# Windows 实战项目 001 文件扫描器 (01)

  - 主要实现功能

    -  搜索系统目录文件

    -  找到文件并打印输出

 

  - 主要使用到的函数

    - FindFirstFile

     函数原型:

1             HANDLE WINAPI FindFirstFile(
2               _In_  LPCTSTR           lpFileName,
3               _Out_ LPWIN32_FIND_DATA lpFindFileData
4             );

      参数1 lpFileName

        搜索的文件名

c:\\Windows\\*.*                                //在c:\\Windows目录中查找所有文件
c:\\Windows\\System32\\*.dll                    //在c:\\Windows\\System32目录中查找所有dll文件
c:\\Windows\\System.ini;                      //在c:\\Windows目录中查找System.ini文件
c:\\Windows\\a???.*                           //在c:\\Windows目录中查找所有以a开头的文件名长度.为4个字符的文件
Test.dat                                    //在当前目录查找Test.dat文件
*.*                                         //在当前目录查找所有文件

      参数2 lpFindFileData

        搜索到文件数据 输出信息的 结构体

      

      返回值

        返回成功

          如果函数返回成功,则返回值是后续调用 FindNextFile 或者 FindClose 时使用的搜索句柄,

          lpFindFileData 参数包含有关找到的第一个文件或目录的信息

        返回失败

          如果函数失败或无法从lpFileName参数中的搜索字符串中找到文件,则返回为 INVALID_HANDLE_VALUE

          并且lpFindFileData的内容不确定的,用 GetLastError 获取操作代码

            如果函数失败,因为找不到匹配文件,GetLastError函数返回 ERROR_FILE_NOT_FOUND;

 

    - FindNextFile

      函数原型

1       HANDLE WINAPI FindFirstFile(
2        _In_  LPCTSTR           lpFileName,
3         _Out_ LPWIN32_FIND_DATA lpFindFileData
4       );

      参数1:lpFileName

          搜索到的文件名字,或者目录名称。不能为空

      参数2 lpFindFileData

        搜索到文件数据 输出信息的 结构体

      

      返回值

        返回成功

          如果函数返回成功,则返回值是后续调用 FindNextFile 或者 FindClose 时使用的搜索句柄,

          lpFindFileData 参数包含有关找到的第一个文件或目录的信息

        返回失败

          如果函数失败或无法从lpFileName参数中的搜索字符串中找到文件,则返回为 INVALID_HANDLE_VALUE

          并且lpFindFileData的内容不确定的,用 GetLastError 获取操作代码

            如果函数失败,因为找不到匹配文件,GetLastError函数返回 ERROR_FILE_NOT_FOUND;

 

    

文件属性常量

文件属性是文件系统在磁盘上存储的元数据值,由系统使用,可通过各种文件I / O API向开发人员提供。有关相关API和主题的列表,请参阅另请参阅部分。

 

恒/值描述
FILE_ATTRIBUTE_ARCHIVE
32(0x20)

作为归档文件或目录的文件或目录。应用程序通常使用此属性来标记文件进行备份或删除。 

FILE_ATTRIBUTE_COMPRESSED
2048(0x800)

被压缩的文件或目录。对于一个文件,文件中的所有数据都被压缩。对于目录,压缩是新创建的文件和子目录的默认值。

FILE_ATTRIBUTE_DEVICE
64(0x40)

此值保留供系统使用。

FILE_ATTRIBUTE_DIRECTORY
16(0x10)

标识目录的句柄。

FILE_ATTRIBUTE_ENCRYPTED
16384(0x4000)

加密的文件或目录。对于一个文件,文件中的所有数据流都被加密。对于目录,加密是新创建的文件和子目录的默认值。

FILE_ATTRIBUTE_HIDDEN
2(0x2)

该文件或目录被隐藏。它不包括在普通目录列表中。

FILE_ATTRIBUTE_INTEGRITY_STREAM
32768(0x8000)

目录或用户数据流配置完整性(仅在ReFS卷上支持)。它不包括在普通目录列表中。如果文件被重命名,则完整性设置将与文件保持一致。如果文件被复制,则如果源文件或目标目录具有完整性集,则目标文件将具有完整性集。

Windows Server 2008 R2,Windows 7,Windows Server 2008,Windows Vista,Windows Server 2003和Windows XP:   Windows Server 2012之前不支持此标志。

FILE_ATTRIBUTE_NORMAL
128(0x80)

没有设置其他属性的文件。此属性仅在单独使用时有效。

FILE_ATTRIBUTE_NOT_CONTENT_INDEXED
8192(0x2000)

文件或目录不被内容索引服务编入索引。

FILE_ATTRIBUTE_NO_SCRUB_DATA
131072(0x20000)

用户数据流不被背景数据完整性扫描器(AKA scrubber)读取。当设置在目录上时,它只提供继承。此标志仅在存储空间和ReFS卷上受支持。它不包括在普通目录列表中。

Windows Server 2008 R2,Windows 7,Windows Server 2008,Windows Vista,Windows Server 2003和Windows XP:   Windows 8和Windows Server 2012之前不支持此标志。

FILE_ATTRIBUTE_OFFLINE
4096(0x1000)

文件的数据不可用。该属性表示文件数据被物理移动到离线存储。该属性由分层存储管理软件Remote Storage使用。应用程序不应该随意更改此属性。

FILE_ATTRIBUTE_READONLY
1(0x1)

只读的文件。应用程序可以读取文件,但不能写入或删除它。该属性不符合目录。有关详细信息,

FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS
4194304(0x400000)

设置此属性时,表示文件或目录在本地不完全存在。对于一个文件,意味着并不是所有的数据都在本地存储上(例如,它可能是稀疏的,还有一些数据仍在远程存储中)。对于目录,这意味着某些目录内容正在从另一个位置进行虚拟化。读取文件/枚举目录将比正常情况更昂贵,例如,将导致至少一些文件/目录内容从远程存储提取。只有内核模式的呼叫者可以设置这个位。

FILE_ATTRIBUTE_RECALL_ON_OPEN
262144(0x40000)

此属性仅显示在目录枚举类(FILE_DIRECTORY_INFORMATION,FILE_BOTH_DIR_INFORMATION等)中。当设置此属性时,表示文件或目录在本地系统上没有物理表示; 该项目是虚拟的。打开该项目将比正常更昂贵,例如,它会导致至少一些从远程商店获取。

FILE_ATTRIBUTE_REPARSE_POINT
1024(0x400)

具有关联重新解析点的文件或目录,或者是符号链接的文件。

FILE_ATTRIBUTE_SPARSE_FILE
512(0x200)

一个稀疏文件的文件。

FILE_ATTRIBUTE_SYSTEM
4(0x4)

操作系统使用部分或专门使用的文件或目录。

FILE_ATTRIBUTE_TEMPORARY
256(0x100)

正在用于临时存储的文件。如果有足够的高速缓存可用,文件系统避免将数据写回大容量存储,因为通常,应用程序在关闭句柄后会删除临时文件。在这种情况下,系统可以完全避免写入数据。否则,手柄关闭后写入数据。

FILE_ATTRIBUTE_VIRTUAL
65536(0x10000)

此值保留供系统使用。

 

  简单使用代码

 1 #include <stdio.h>
 2 #include <windows.h>
 3 #include <string>
 4 
 5 int main()
 6 {
 7     std::wstring wstrBeginDirName = L"C:\\\\*.*";
 8     std::wstring wstrSearchName = L"ntdll";
 9 
10     WIN32_FIND_DATAW findFile = { 0 };
11 
12     HANDLE hFileFind  = FindFirstFileW(wstrBeginDirName.c_str(), &findFile);
13 
14     do
15     {
16         printf("File name: %ls \\r\\n", findFile.cFileName);
17     } while (FindNextFileW(hFileFind, &findFile));
18 
19     system("pause");
20     return 0;
21 }

 

判断是否是文件夹

 1 #include <stdio.h>
 2 #include <windows.h>
 3 #include <string>
 4 
 5 int main()
 6 {
 7     system("color b");
 8     std::wstring wstrBeginDirName = L"C:\\\\*.*";
 9     std::wstring wstrSearchName = L"ntdll";
10 
11     WIN32_FIND_DATAW findFile = { 0 };
12 
13     HANDLE hFileFind  = FindFirstFileW(wstrBeginDirName.c_str(), &findFile);
14 
15     do
16     {
17         if (findFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
18             printf("Dir \\t\\t\\t %ls \\r\\n", findFile.cFileName);
19         else
20             printf("File \\t\\t\\t %ls \\r\\n", findFile.cFileName);
21     } while (FindNextFileW(hFileFind, &findFile));
22 
23     system("pause");
24     return 0;
25 }

 

  重点:

    findFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY

      findFile.dwFileAttributes 一个多值的 不能使用 == 

      FILE_ATTRIBUTE_DIRECTORY  常量 16(0x10) 进行逻辑与运算

 

递归搜索

 1 // Everything.cpp : 定义控制台应用程序的入口点。
 2 //
 3 
 4 #include "stdafx.h"
 5 #include <stdio.h>
 6 #include <windows.h>
 7 #include <string>
 8 
 9 //递归的方法继续搜索
10 unsigned g_nFindedFileNum = 0;
11 unsigned g_nSearchFileNum = 0;
12 unsigned g_nSearchDirNum = 0;
13 
14 std::wstring MakeStandardDirName(const std::wstring &wstrDirname)
15 {
16     if (wstrDirname.back() != \'\\\\\')
17         return wstrDirname + L"\\\\";
18     return wstrDirname;
19 }
20 void MyFileFind(std::wstring &wstrBeginDirName, std::wstring &wstrSearch, std::wstring wstrFile = L"*.*")
21 {
22 
23     WIN32_FIND_DATAW findFile = { 0 };
24 
25     HANDLE hFileFind = FindFirstFileW((MakeStandardDirName(wstrBeginDirName)+wstrFile).c_str(), &findFile);
26 
27     do
28     {
29         if (wcscmp(findFile.cFileName, L".") == 0)
30             continue;
31         if (wcscmp(findFile.cFileName, L"..") == 0)
32             continue;
33         if (findFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
34             //printf("Dir \\t\\t\\t %ls \\r\\n", findFile.cFileName);
35         {
36             MyFileFind(MakeStandardDirName(wstrBeginDirName) + findFile.cFileName, wstrSearch);
37             g_nSearchDirNum++;
38         }
39         else
40             //printf("File \\t\\t\\t %ls \\r\\n", findFile.cFileName);
41         {
42             if (wcsstr(findFile.cFileName, wstrSearch.c_str()) != nullptr)
43             {
44                 printf("Searched File In:\\t %ls \\r\\n",(MakeStandardDirName(wstrBeginDirName)+findFile.cFileName).c_str());
45                 g_nFindedFileNum++;
46             }
47             g_nSearchFileNum++;
48         }
49     } while (FindNextFileW(hFileFind, &findFile));
50 
51 //    return g_nFindedFileNum;
52 }
53 
54 int main()
55 {
56     system("color b");
57     std::wstring wstrBeginDirName = L"C:\\\\";
58     std::wstring wstrSearchName = L"ntdll";
59 
60     DWORD dwBegin = GetTickCount();
61     MyFileFind(wstrBeginDirName, wstrSearchName);
62 
63     DWORD dwTime = GetTickCount() - dwBegin;
64     printf("耗费时间:%d(秒)\\r\\n合计找到:%d个文件\\r\\n共遍历过%d个文件夹和%d个文件!\\r\\n",
65         dwTime/1000, g_nFindedFileNum, g_nSearchDirNum, g_nSearchFileNum);
66 
67     system("pause");
68     return 0;
69 }

 

  重点:

    if (wcsstr(findFile.cFileName, wstrSearch.c_str()) != nullptr)

      比较字符串 是否存在,文件名称是否匹配

 

递归的实现方法

 1 // Everything.cpp : 定义控制台应用程序的入口点。
 2 //
 3 
 4 #include "stdafx.h"
 5 #include <stdio.h>
 6 #include <windows.h>
 7 #include <string>
 8 #include <process.h>
 9 
10 //递归的方法继续搜索
11 unsigned g_nFindedFileNum = 0;
12 unsigned g_nSearchFileNum = 0;
13 unsigned g_nSearchDirNum = 0;
14 
15 std::wstring MakeStandardDirName(const std::wstring &wstrDirname)
16 {
17     if (wstrDirname.back() != \'\\\\\')
18         return wstrDirname + L"\\\\";
19     return wstrDirname;
20 }
21 void MyFileFind(std::wstring &wstrBeginDirName, std::wstring &wstrSearch, std::wstring wstrFile = L"*.*")
22 {
23 
24     WIN32_FIND_DATAW findFile = { 0 };
25 
26     HANDLE hFileFind = FindFirstFileW((MakeStandardDirName(wstrBeginDirName)+wstrFile).c_str(), &findFile);
27 
28     do
29     {
30         if (wcscmp(findFile.cFileName, L".") == 0)
31             continue;
32         if (wcscmp(findFile.cFileName, L"..") == 0)
33             continue;
34         if (findFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
35             //printf("Dir \\t\\t\\t %ls \\r\\n", findFile.cFileName);
36         {
37             MyFileFind(MakeStandardDirName(wstrBeginDirName) + findFile.cFileName, wstrSearch);
38             g_nSearchDirNum++;
39         }
40         else
41             //printf("File \\t\\t\\t %ls \\r\\n", findFile.cFileName);
42         {
43             if (wcsstr(findFile.cFileName, wstrSearch.c_str()) != nullptr)
44             {
45                 printf("Searched File In:\\t %ls \\r\\n",(MakeStandardDirName(wstrBeginDirName)+findFile.cFileName).c_str());
46                 g_nFindedFileNum++;
47             }
48             g_nSearchFileNum++;
49         }
50     } while (FindNextFileW(hFileFind, &findFile));
51 
52 //    return g_nFindedFileNum;
53 }
54 
55 int main()
56 {
57     system("color b");
58     std::wstring wstrBeginDirName = L"C:\\\\";
59     std::wstring wstrSearchName = L"ntdll";
60 
61     DWORD dwBegin = GetTickCount();
62     MyFileFind(wstrBeginDirName, wstrSearchName);
63 
64     DWORD dwTime = GetTickCount() - dwBegin;
65     printf("耗费时间:%d(秒)\\r\\n合计找到:%d个文件\\r\\n共遍历过%d个文件夹和%d个文件!\\r\\n",
66         dwTime/1000, g_nFindedFileNum, g_nSearchDirNum, g_nSearchFileNum);
67 
68     system("pause");
69     return 0;
70 }

 

多线程实现发放

 

// Everything.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <stdio.h>
#include <string>
#include <process.h>
#include <vector>
#include <windows.h>

//递归的方法继续搜索
//unsigned g_nFindedFileNum = 0;
//unsigned g_nSearchFileNum = 0;
//unsigned g_nSearchDirNum = 0;

std::wstring MakeStandardDirName(const std::wstring &wstrDirname)
{
    if (wstrDirname.back() != \'\\\\\')
        return wstrDirname + L"\\\\";
    return wstrDirname;
}
//void MyFileFind(std::wstring &wstrBeginDirName, std::wstring &wstrSearch, std::wstring wstrFile = L"*.*")
//{
//
//    WIN32_FIND_DATAW findFile = { 0 };
//
//    HANDLE hFileFind = FindFirstFileW((MakeStandardDirName(wstrBeginDirName) + wstrFile).c_str(), &findFile);
//
//    do
//    {
//        if (wcscmp(findFile.cFileName, L".") == 0)
//            continue;
//        if (wcscmp(findFile.cFileName, L"..") == 0)
//            continue;
//        if (findFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
//            //printf("Dir \\t\\t\\t %ls \\r\\n", findFile.cFileName);
//        {
//            MyFileFind(MakeStandardDirName(wstrBeginDirName) + findFile.cFileName, wstrSearch);
//            g_nSearchDirNum++;
//        }
//        else
//            //printf("File \\t\\t\\t %ls \\r\\n", findFile.cFileName);
//        {
//            if (wcsstr(findFile.cFileName, wstrSearch.c_str()) != nullptr)
//            {
//                printf("Searched File In:\\t %ls \\r\\n", (MakeStandardDirName(wstrBeginDirName) + findFile.cFileName).c_str());
//                g_nFindedFileNum++;
//            }
//            g_nSearchFileNum++;
//        }
//    } while (FindNextFileW(hFileFind, &findFile));

    //    return g_nFindedFileNum;
//}

HANDLE g_hExitEvent;
std::vector<HANDLE> g_hThreads;

CRITICAL_SECTION g_cs;

long g_lFindedFileNum = 0;
long g_lSearchFileNum = 0;
long g_lSearchDirNum = 0;
long g_lWorkThreadNum = 0;

struct ThreadData
{
    std::wstring wstrDirName;
    std::wstring wstrSearch;
    std::wstring wstrFile; 
};

unsigned __stdcall ThreadFileFind(void *lParam)
{
    InterlockedAdd(&g_lWorkThreadNum, 1);

    ThreadData *pData = (ThreadData*)lParam;

    WIN32_FIND_DATAW fileFind = { 0 };
    HANDLE hFileFind = FindFirstFileW(
        (MakeStandardDirName(pData->wstrDirName) + pData->wstrFile).c_str(), &fileFind);
    do
    {
        if (wcscmp(fileFind.cFileName, L".") == 0)
            continue;
        if (wcscmp(fileFind.cFileName, L"..") == 0)
            continue;
        if (fileFind.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
        {
            ThreadData *pTempData = new ThreadData;
            pTempData->wstrDirName = MakeStandardDirName(pData->wstrDirName) + fileFind.cFileName;
            pTempData->wstrFile = pData->wstrFile;
            pTempData->wstrSearch = pData->wstrSearch;

            //上锁
            EnterCriticalSection(&g_cs);

            CloseHandle((HANDLE)_beginthreadex(nullptr, 0, ThreadFileFind, pTempData, 0, nullptr));
            //g_hThreads.push_back((HANDLE)_beginthreadex(nullptr, 0, ThreadFileFind, pTempData, 0, nullptr));

            LeaveCriticalSection(&g_cs);

            //原子操作
            InterlockedAdd(&g_lSearchDirNum, 1);
        }
        else
        {
            if(wcsstr(fileFind.cFileName,pData->wstrSearch.c_str()) != nullptr)
            {
                printf("Searched File In:\\t %ls \\r\\n", (MakeStandardDirName(pData->wstrDirName) + fileFind.cFileName).c_str());
                InterlockedAdd(&g_lFindedFileNum, 1);
            }
            InterlockedAdd(&g_lSearchFileNum, 1);
        }

    } while (FindNextFileW(hFileFind,&fileFind));
    delete pData;

    InterlockedAdd(&g_lWorkThreadNum, -1);
    if (g_lWorkThreadNum == 0)
        SetEvent(g_hExitEvent);
    return 0;
}

int main()
{
    //初始化锁
    InitializeCriticalSection(&g_cs);

    g_hExitEvent =  CreateEvent(nullptr, FALSE, FALSE, nullptr);

    ThreadData *pTempData = new ThreadData;
    pTempData->wstrDirName = L"C:";
    pTempData->wstrFile = L"*.*";
    pTempData->wstrSearch = L"ntdll";

    DWORD dwBegin = GetTickCount();
    CloseHandle((HANDLE)_beginthreadex(nullptr, 0, ThreadFileFind, pTempData, 0, nullptr));
    //g_hThreads.push_back((HANDLE)_beginthreadex(nullptr, 0, ThreadFileFind, pTempData, 0, nullptr));

    //WaitForMultipleObjects(g_hThreads.size(), g_hThreads.data(), TRUE, INFINITE);

    WaitForSingleObject(g_hExitEvent, INFINITE);

    DWORD dwTime = GetTickCount() - dwBegin;

    //关闭句柄
    for (auto g_h_thread : g_hThreads)
    {
        CloseHandle(g_h_thread);
    }

    DeleteCriticalSection(&g_cs);


    printf("耗费时间:%d(秒)\\r\\n合计找到:%d个文件\\r\\n共遍历过%d个文件夹和%d个文件!\\r\\n",
        dwTime / 1000, g_lFindedFileNum, g_lSearchDirNum, g_lSearchFileNum);

    //什么时候搜索完成

    //system("color b");
    //std::wstring wstrBeginDirName = L"C:\\\\";
    //std::wstring wstrSearchName = L"ntdll";

    //DWORD dwBegin = GetTickCount();
    //MyFileFind(wstrBeginDirName, wstrSearchName);

    //DWORD dwTime = GetTickCount() - dwBegin;
    //printf("耗费时间:%d(秒)\\r\\n合计找到:%d个文件\\r\\n共遍历过%d个文件夹和%d个文件!\\r\\n",
    //    dwTime / 1000, g_nFindedFileNum, g_nSearchDirNum, g_nSearchFileNum);

    system("pause");
    return 0;
}

 

以上是关于Windows 实战项目 001 文件扫描器 (01)的主要内容,如果未能解决你的问题,请参考以下文章

便宜出课!C++视频windows界面UI编程MFCGDI自绘项目实战网络编程教程我有原版

001 python基础实战

Android实战——Zxing实现二维码扫描

独立开发人员er Cocos2d-x实战 001csb文件导出和载入

Windows跳过扫描阶段,直接删除文件

Windows跳过扫描阶段,直接删除文件