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 #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 }

 

多线程实现方法

  1 // Everything.cpp : 定义控制台应用程序的入口点。
  2 //
  3 
  4 #include "stdafx.h"
  5 #include <stdio.h>
  6 #include <string>
  7 #include <process.h>
  8 #include <vector>
  9 #include <windows.h>
 10 
 11 //递归的方法继续搜索
 12 //unsigned g_nFindedFileNum = 0;
 13 //unsigned g_nSearchFileNum = 0;
 14 //unsigned g_nSearchDirNum = 0;
 15 
 16 std::wstring MakeStandardDirName(const std::wstring &wstrDirname)
 17 {
 18     if (wstrDirname.back() != '\\')
 19         return wstrDirname + L"\\";
 20     return wstrDirname;
 21 }
 22 //void MyFileFind(std::wstring &wstrBeginDirName, std::wstring &wstrSearch, std::wstring wstrFile = L"*.*")
 23 //{
 24 //
 25 //    WIN32_FIND_DATAW findFile = { 0 };
 26 //
 27 //    HANDLE hFileFind = FindFirstFileW((MakeStandardDirName(wstrBeginDirName) + wstrFile).c_str(), &findFile);
 28 //
 29 //    do
 30 //    {
 31 //        if (wcscmp(findFile.cFileName, L".") == 0)
 32 //            continue;
 33 //        if (wcscmp(findFile.cFileName, L"..") == 0)
 34 //            continue;
 35 //        if (findFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
 36 //            //printf("Dir \t\t\t %ls \r\n", findFile.cFileName);
 37 //        {
 38 //            MyFileFind(MakeStandardDirName(wstrBeginDirName) + findFile.cFileName, wstrSearch);
 39 //            g_nSearchDirNum++;
 40 //        }
 41 //        else
 42 //            //printf("File \t\t\t %ls \r\n", findFile.cFileName);
 43 //        {
 44 //            if (wcsstr(findFile.cFileName, wstrSearch.c_str()) != nullptr)
 45 //            {
 46 //                printf("Searched File In:\t %ls \r\n", (MakeStandardDirName(wstrBeginDirName) + findFile.cFileName).c_str());
 47 //                g_nFindedFileNum++;
 48 //            }
 49 //            g_nSearchFileNum++;
 50 //        }
 51 //    } while (FindNextFileW(hFileFind, &findFile));
 52 
 53     //    return g_nFindedFileNum;
 54 //}
 55 
 56 HANDLE g_hExitEvent;
 57 std::vector<HANDLE> g_hThreads;
 58 
 59 CRITICAL_SECTION g_cs;
 60 
 61 long g_lFindedFileNum = 0;
 62 long g_lSearchFileNum = 0;
 63 long g_lSearchDirNum = 0;
 64 long g_lWorkThreadNum = 0;
 65 
 66 struct ThreadData
 67 {
 68     std::wstring wstrDirName;
 69     std::wstring wstrSearch;
 70     std::wstring wstrFile; 
 71 };
 72 
 73 unsigned __stdcall ThreadFileFind(void *lParam)
 74 {
 75     InterlockedAdd(&g_lWorkThreadNum, 1);
 76 
 77     ThreadData *pData = (ThreadData*)lParam;
 78 
 79     WIN32_FIND_DATAW fileFind = { 0 };
 80     HANDLE hFileFind = FindFirstFileW(
 81         (MakeStandardDirName(pData->wstrDirName) + pData->wstrFile).c_str(), &fileFind);
 82     do
 83     {
 84         if (wcscmp(fileFind.cFileName, L".") == 0)
 85             continue;
 86         if (wcscmp(fileFind.cFileName, L"..") == 0)
 87             continue;
 88         if (fileFind.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
 89         {
 90             ThreadData *pTempData = new ThreadData;
 91             pTempData->wstrDirName = MakeStandardDirName(pData->wstrDirName) + fileFind.cFileName;
 92             pTempData->wstrFile = pData->wstrFile;
 93             pTempData->wstrSearch = pData->wstrSearch;
 94 
 95             //上锁
 96             EnterCriticalSection(&g_cs);
 97 
 98             CloseHandle((HANDLE)_beginthreadex(nullptr, 0, ThreadFileFind, pTempData, 0, nullptr));
 99             //g_hThreads.push_back((HANDLE)_beginthreadex(nullptr, 0, ThreadFileFind, pTempData, 0, nullptr));
100 
101             LeaveCriticalSection(&g_cs);
102 
103             //原子操作
104             InterlockedAdd(&g_lSearchDirNum, 1);
105         }
106         else
107         {
108             if(wcsstr(fileFind.cFileName,pData->wstrSearch.c_str()) != nullptr)
109             {
110                 printf("Searched File In:\t %ls \r\n", (MakeStandardDirName(pData->wstrDirName) + fileFind.cFileName).c_str());
111                 InterlockedAdd(&g_lFindedFileNum, 1);
112             }
113             InterlockedAdd(&g_lSearchFileNum, 1);
114         }
115 
116     } while (FindNextFileW(hFileFind,&fileFind));
117     delete pData;
118 
119     InterlockedAdd(&g_lWorkThreadNum, -1);
120     if (g_lWorkThreadNum == 0)
121         SetEvent(g_hExitEvent);
122     return 0;
123 }
124 
125 int main()
126 {
127     //初始化锁
128     InitializeCriticalSection(&g_cs);
129 
130     g_hExitEvent =  CreateEvent(nullptr, FALSE, FALSE, nullptr);
131 
132     ThreadData *pTempData = new ThreadData;
133     pTempData->wstrDirName = L"C:";
134     pTempData->wstrFile = L"*.*";
135     pTempData->wstrSearch = L"ntdll";
136 
137     DWORD dwBegin = GetTickCount();
138     CloseHandle((HANDLE)_beginthreadex(nullptr, 0, ThreadFileFind, pTempData, 0, nullptr));
139     //g_hThreads.push_back((HANDLE)_beginthreadex(nullptr, 0, ThreadFileFind, pTempData, 0, nullptr));
140 
141     //WaitForMultipleObjects(g_hThreads.size(), g_hThreads.data(), TRUE, INFINITE);
142 
143     WaitForSingleObject(g_hExitEvent, INFINITE);
144 
145     DWORD dwTime = GetTickCount() - dwBegin;
146 
147     //关闭句柄
148     for (auto g_h_thread : g_hThreads)
149     {
150         CloseHandle(g_h_thread);
151     }
152 
153     DeleteCriticalSection(&g_cs);
154 
155 
156     printf("耗费时间:%d(秒)\r\n合计找到:%d个文件\r\n共遍历过%d个文件夹和%d个文件!\r\n",
157         dwTime / 1000, g_lFindedFileNum, g_lSearchDirNum, g_lSearchFileNum);
158 
159     //什么时候搜索完成
160 
161     //system("color b");
162     //std::wstring wstrBeginDirName = L"C:\\";
163     //std::wstring wstrSearchName = L"ntdll";
164 
165     //DWORD dwBegin = GetTickCount();
166     //MyFileFind(wstrBeginDirName, wstrSearchName);
167 
168     //DWORD dwTime = GetTickCount() - dwBegin;
169     //printf("耗费时间:%d(秒)\r\n合计找到:%d个文件\r\n共遍历过%d个文件夹和%d个文件!\r\n",
170     //    dwTime / 1000, g_nFindedFileNum, g_nSearchDirNum, g_nSearchFileNum);
171 
172     system("pause");
173     return 0;
174 }

 

posted @ 2017-08-16 15:34  ☆﹎夜﹎☆  阅读(87)  评论(0编辑  收藏  举报