簡體   English   中英

如何使用 Windows API 列出目錄中的文件?

[英]How to list files in a directory using the Windows API?

我有這個代碼,它顯示文件夾本身而不是它的內容。 我想顯示它的內容。 我不想使用 boost::filesystem。

我該如何解決這個問題?

代碼:

#include <windows.h>
#include <iostream>

int main()
{
    WIN32_FIND_DATA data;
    HANDLE hFind = FindFirstFile("C:\\semester2", &data);      // DIRECTORY

    if ( hFind != INVALID_HANDLE_VALUE ) {
        do {
            std::cout << data.cFileName << std::endl;
        } while (FindNextFile(hFind, &data));
        FindClose(hFind);
    }
}

輸出:

semester2
HANDLE hFind = FindFirstFile("C:\\semester2", &data);       // DIRECTORY

你得到了目錄,因為那是你所要求的。 如果您想要這些文件,請索取:

HANDLE hFind = FindFirstFile("C:\\semester2\\*", &data);  // FILES

(如果您願意,您可以改為使用*.* ,但顯然這僅適用於向后兼容性黑客,因此應該避免使用。請參閱評論和 RbMm 的答案。)

讓我做一些關於"*.*""*"筆記。 這些申報者並不相等。

我們的文件夾中可以存在 2 個不同的文件: somefilesomefile. .

如果我們使用帶有"*.*"的低級 API ZwQueryDirectoryFile作為搜索表達式(這是第 10 個參數 - FileName [in, optional] ) - 我們將得到一些文件somefile. 只要。 但是如果我們使用"*"我們會得到兩個文件somefilesomefile.

如果我們嘗試FindFirstFile("C:\\\\semester2\\\\*.*", &data); 我們可以注意到兩個文件somefilesomefile. 被退回。 所以這里"*.*""*"具有相同的效果 - 用法沒有區別。

為什么會發生這種情況? 因為在kernelbasekernel32 )中的FindFirstFileEx內對"*.*"掩碼進行特殊檢查,如果為真 - 替換為"" (與"*"具有相同效果的空名稱)。

我認為這樣做是為了在用戶傳遞"*.*"而不是正確的"*"時修復一個非常常見的錯誤,以及與遺留代碼的向后兼容性。

. ..實際上不是目錄的一部分,因為它存儲在磁盤上,而是由 Win32 API 添加的。

這不是真的。

  • 對於FAT樣式的文件系統,這實際上作為第 2 個條目存儲在 FAT 目錄中。
  • NTFS中沒有這樣的條目,但NTFS.sys人為地添加了這 2 個條目,如果它們在掩碼中。

所以這不是在 Win32 API 級別完成的,而是在內核 - 在驅動程序級別完成的。

總之, "*.*"可以在 Win32 API 中正常工作,但正確且干凈的方法是在此處使用"*"
"*.*"將與ZwQueryDirectoryFile api 錯誤。

這是一個示例實現:

#include <iostream>
#include <vector>
#include <string>
#include <Windows.h>

std::vector<std::string>
list_directory(
    const std::string &directory)
{
    WIN32_FIND_DATAA findData;
    HANDLE hFind = INVALID_HANDLE_VALUE;
    std::string full_path = directory + "\\*";
    std::vector<std::string> dir_list;

    hFind = FindFirstFileA(full_path.c_str(), &findData);

    if (hFind == INVALID_HANDLE_VALUE)
        throw std::runtime_error("Invalid handle value! Please check your path...");

    while (FindNextFileA(hFind, &findData) != 0)
    {
        dir_list.push_back(std::string(findData.cFileName));
    }

    FindClose(hFind);

    return dir_list;
}

注意:如果您使用 C++ 11 或 std::filesystem 如果您使用 C++ 17,最好使用類似 boost::filesystem 的東西。此外,輸入路徑必須像 C:\\path 而不是 C:\\path\\否則這行不通!!

Harrys 的回答實際上會在您想要的文件夾"C:\\\\semester2"產生具有擴展名的文件和文件夾。

例如,如果您有一個名為"C:\\\\semester2\\\\math.course"的文件夾,上面的示例也可以找到它。 此外,如果您有一個名為"C:\\\\semester2\\\\math_scores" (注意它沒有擴展名),它將找不到。

考慮到上述情況,我建議以下解決方案:

HANDLE hFind = FindFirstFile("C:\\semester2\\*", &data); 

這將列出目錄下項目的完整列表。 可以通過以下方式過濾目錄:

if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
// directory
}
else
{
// file
}

以下可用於參考: FileAttributes 常量FIND_DATA structFindFirstFile API

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM