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

时间:2016-12-31 01:42:29

标签: c++ windows winapi

我有这个代码,它显示了目录本身的文件夹,而不是其内容。我想显示它的内容。我不想使用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

4 个答案:

答案 0 :(得分:13)

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

你有这个目录,因为那就是你要求的。如果你想要这些文件,请询问:

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

(如果您愿意,可以使用*.*,但显然这只是因为向后兼容性黑客而有效,所以应该避免。请参阅评论和RbMm的答案。)

答案 1 :(得分:6)

让我对"*.*" vs "*"做一些说明。这些报送者不相等。

我们的文件夹中可以存在2个不同的文件:somefilesomefile.

如果我们使用低级别的api ZwQueryDirectoryFile"*.*"作为搜索表达式(这是第10个参数 - FileName [in, optional] ) - 我们会得到{仅限{1}}。但是,如果我们使用somefile.,我们会同时获取这两个文件 - "*"somefile

如果我们尝试somefile.,我们可以注意到,返回文件FindFirstFile("C:\\semester2\\*.*", &data);somefile。因此somefile. vs "*.*"具有相同的效果 - 使用方式没有差异。

为什么会这样?因为"*"FindFirstFileEx)中的kernelbase内部会对kernel32掩码进行特殊检查,如果为真,则替换为"*.*"(具有相同名称的空名称)效果为"")。

我认为这样可以解决用户通过"*"而不是正确的"*.*"时出现的非常常见的错误,以及与遗留代码的向后兼容性。

  

"*".实际上并不是目录的一部分,因为它存储在   磁盘,但是由Win32 API添加。

事实并非如此。

  • 对于.. - 样式文件系统,它实际上存储在FAT目录中作为第一个条目。
  • FAT中没有这样的条目,但NTFS人工添加这两个条目(如果它们在掩码中)。

所以这不是在Win32 API级别,而是在内核 - 驱动程序级别。

总而言之,NTFS.sys在Win32 API方面的工作正常至关重要 - 但正确而干净的方法是在此处使用"*.*"
"*" api会错误"*.*"

答案 2 :(得分:1)

这是一个示例实现:

#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\ 否则这将不起作用!!

答案 3 :(得分:0)

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 constantsFIND_DATA structFindFirstFile API