[英]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 個不同的文件: somefile
和somefile.
.
如果我們使用帶有"*.*"
的低級 API ZwQueryDirectoryFile
作為搜索表達式(這是第 10 個參數 - FileName [in, optional]
) - 我們將得到一些文件somefile.
只要。 但是如果我們使用"*"
我們會得到兩個文件somefile
和somefile.
如果我們嘗試FindFirstFile("C:\\\\semester2\\\\*.*", &data);
我們可以注意到兩個文件somefile
和somefile.
被退回。 所以這里"*.*"
與"*"
具有相同的效果 - 用法沒有區別。
為什么會發生這種情況? 因為在kernelbase
( kernel32
)中的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 struct 、 FindFirstFile API
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.