1. 程式人生 > >Windows 實戰項目 001 文件掃描器 (01)

Windows 實戰項目 001 文件掃描器 (01)

push stream ber log 遍歷 解析 index sig 其他

---恢復內容開始---

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