如何使用C++在Windows中列出子目录?

11
如何使用C++在Windows中列出子目录?最好使用可跨平台运行的代码。

4
首先,你需要搜索,然后尝试一些东西,最后发布你卡住的代码。 - Mitch Wheat
4
“跨平台”是什么意思?http://www.boost.org/doc/libs/1_40_0/libs/filesystem/doc/index.htm - Etienne de Martel
1
@Etienne:为什么要链接到将近两年前的版本文档?Boost.Filesystem的API从那时起发生了显著变化(v3与v2),因此值得链接到当前文档 - ildjarn
1
@avee:你说你想要一个Windows的解决方案,最好是跨平台的,并且遵循POSIX标准?下定决心吧... ;-] (真的,选一个吧。) - ildjarn
显示剩余4条评论
6个回答

8

这是我针对这个问题的解决方案,但它只适用于Windows操作系统。我希望能够使用跨平台的解决方案,但不想使用boost。

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

/// Gets a list of subdirectories under a specified path
/// @param[out] output Empty vector to be filled with result
/// @param[in]  path   Input path, may be a relative path from working dir
void getSubdirs(std::vector<std::string>& output, const std::string& path)
{
    WIN32_FIND_DATA findfiledata;
    HANDLE hFind = INVALID_HANDLE_VALUE;

    char fullpath[MAX_PATH];
    GetFullPathName(path.c_str(), MAX_PATH, fullpath, 0);
    std::string fp(fullpath);

    hFind = FindFirstFile((LPCSTR)(fp + "\\*").c_str(), &findfiledata);
    if (hFind != INVALID_HANDLE_VALUE)
    {
        do 
        {
            if ((findfiledata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0
                && (findfiledata.cFileName[0] != '.'))
            {
                output.push_back(findfiledata.cFileName);
            }
        } 
        while (FindNextFile(hFind, &findfiledata) != 0);
    }
}

/// Gets a list of subdirectory and their subdirs under a specified path
/// @param[out] output Empty vector to be filled with result
/// @param[in]  path   Input path, may be a relative path from working dir
/// @param[in]  prependStr String to be pre-appended before each result
///                        for top level path, this should be an empty string
void getSubdirsRecursive(std::vector<std::string>& output, 
                         const std::string& path,
                         const std::string& prependStr)
{
    std::vector<std::string> firstLvl;
    getSubdirs(firstLvl, path);
    for (std::vector<std::string>::iterator i = firstLvl.begin(); 
         i != firstLvl.end(); ++i)
    {
        output.push_back(prependStr + *i);
        getSubdirsRecursive(output, 
            path + std::string("\\") + *i + std::string("\\"),
            prependStr + *i + std::string("\\"));
    }
}

谢谢回答,非常有帮助。 - user6952310
该算法无法检测具有自定义图标的文件夹。 - Mahdi-Malv
一个非常有 bug 的算法,抱歉 :) - Alexander Dyagilev
1
该算法似乎正确使用递归,但是getSubdirs不能可靠地检测文件是否是目录类型。以下if条件不正确: if (findfiledata.dwFileAttributes | FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)将有问题的if条件更改为使用以下条件,可以使该算法对我有效可靠: if (findfiledata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)请参阅 https://learn.microsoft.com/en-us/windows/win32/fileio/listing-the-files-in-a-directory 以获取更多详细信息。 - mbuster

4

这个解决方案相对较好,并且应该可以跨平台使用。您需要更改代码中希望执行某些操作的部分,但除此之外,它应该可以很好地工作。

#include <cstring>
#include <io.h>
#include <iostream>
#include <stdio.h>

using namespace std;

void list(char* dir)
{
    char originalDirectory[_MAX_PATH];

    // Get the current directory so we can return to it
    _getcwd(originalDirectory, _MAX_PATH);

    _chdir(dir);  // Change to the working directory
    _finddata_t fileinfo;

    // This will grab the first file in the directory
    // "*" can be changed if you only want to look for specific files
    intptr_t handle = _findfirst("*", &fileinfo);

    if(handle == -1)  // No files or directories found
    {
        perror("Error searching for file");
        exit(1);
    }

    do
    {
        if(strcmp(fileinfo.name, ".") == 0 || strcmp(fileinfo.name, "..") == 0)
            continue;
        if(fileinfo.attrib & _A_SUBDIR) // Use bitmask to see if this is a directory
            cout << "This is a directory." << endl;
        else
            cout << "This is a file." << endl;
    } while(_findnext(handle, &fileinfo) == 0);

    _findclose(handle); // Close the stream

    _chdir(originalDirectory);
}

int main()
{
    list("C:\\");
    return 0;
}

这是非常简洁的代码,将列出目录中的所有子目录和文件。如果您想要它列出每个子目录中的所有内容,您可以通过在打印“这是一个目录”行时传递子目录来递归调用该函数。类似于list(fileinfo.name)应该能解决问题。


4
这里是一个有关Windows系统编程的链接。
这个链接则介绍了Windows系统编程中的跨平台问题,可以在Windows Vista/7甚至XP上使用。

隐藏的技巧是,GetFileAttributes将指示文件是目录还是常规文件。此外,这个解决方案肯定可以在XP上运行。(并且很可能也适用于Windows 95)。 - selbie
@selbie,你还可以检查上述函数结果中的WIN32_FIND_DATA.dwFileAttributes部分,以获取FILE_ATTRIBUTE_DIRECTORY值,以检查结果是否为目录。此外,你还应该检查...,因为它们也作为结果返回。 - avee
选择这个答案,因为这是我在解决方案中实际使用的。 - avee

4

从2022年开始使用

std::filesystem::directory_iterator

例如:
#include <filesystem>
using namespace std::filesystem;

path sandbox = "sandbox";
create_directories(sandbox/"dir1"/"dir2");

// directory_iterator can be iterated using a range-for loop
for (auto const& dir_entry : directory_iterator{sandbox}){
    if(dir_entry.is_directory()){ //checking if dir or file.
       std::cout << dir_entry << '\n';
    }
}

请记住,还有其他的注意事项。
std::filesystem::recursive_directory_iterator

这个功能用于一次性遍历所有嵌套的子目录。

https://en.cppreference.com/w/cpp/filesystem/directory_iterator


1
现在我也使用这个解决方案。当std::filesystem不可用时,可以采用https://github.com/gulrak/filesystem作为替代方案。我已经在生产环境中使用过它,非常稳定。 - avee

1

-1

你可以使用dirent库。更多细节请参见这里


您介意在答案中包含链接文章的相关部分吗?链接可能会改变,使您的答案对未来读者没有用处。另请参见[答案]。 - CMW

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接