如何使用 C 或 C++ 获取目录中的文件列表?

How can I get the list of files in a directory using C or C++?

提问人:samoz 提问时间:3/5/2009 最后编辑:samoz 更新时间:7/26/2023 访问量:1282765

问:

如何从 C 或 C++ 代码中确定目录中的文件列表?

我不被允许执行命令并从我的程序中解析结果。ls

C++ C 文件 目录

评论

8赞 chrish 3/5/2009
这是609236的副本
1赞 Jonathan Leffler 12/25/2014
另请参阅 stat() 错误 'no such file or directory' when file name is returned by readdir())。
4赞 James Bedford 10/22/2016
@chrish - 是的,但这个有经典的“我不被允许执行'ls'”!这正是我在计算机科学第一年的感受。;D<3 x
7赞 MD XF 3/3/2017
C 和 C++ 不是同一种语言。因此,完成此任务的过程在两种语言中会有所不同。请选择一个并相应地重新标记。
4赞 Toby Speight 2/20/2018
而且这些语言(除了C++,C++17以来)都没有目录的概念 - 因此任何答案都可能取决于您的操作系统或您可能使用的任何抽象库。

答:

11赞 Tim 3/5/2009 #1

尝试 boost for x-platform 方法

http://www.boost.org/doc/libs/1_38_0/libs/filesystem/doc/index.htm

或者只使用您的操作系统特定文件。

评论

3赞 ice1000 6/28/2018
虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。- 来自评论
0赞 Tim 6/28/2018
@ice1000 严重地?此问答来自 2009 年
240赞 Brian R. Bondy 3/5/2009 #2

遗憾的是,C++ 标准没有定义以这种方式处理文件和文件夹的标准方法。

由于没有跨平台的方式,所以最好的跨平台方式是使用诸如boost文件系统模块之类的库。

跨平台boost方式:

以下函数给定目录路径和文件名,以递归方式在目录及其子目录中搜索文件名,返回布尔值,如果成功,则返回找到的文件的路径。

bool find_file(const path & dir_path,         // in this directory,
               const std::string & file_name, // search for this name,
               path & path_found)             // placing path here if found
{
    if (!exists(dir_path)) 
        return false;

    directory_iterator end_itr; // default construction yields past-the-end

    for (directory_iterator itr(dir_path); itr != end_itr; ++itr)
    {
        if (is_directory(itr->status()))
        {
            if (find_file(itr->path(), file_name, path_found)) 
                return true;
        }
        else if (itr->leaf() == file_name) // see below
        {
            path_found = itr->path();
            return true;
        }
    }
    return false;
}

来源于上面提到的提升页面。

对于基于 Unix/Linux 的系统:

你可以使用 opendir / readdir / closedir

在目录中搜索条目 ''name'' 的示例代码如下:

len = strlen(name);
dirp = opendir(".");
while ((dp = readdir(dirp)) != NULL)
        if (dp->d_namlen == len && !strcmp(dp->d_name, name)) {
                (void)closedir(dirp);
                return FOUND;
        }
(void)closedir(dirp);
return NOT_FOUND;

源代码来自上述手册页。

对于基于 Windows 的系统:

可以使用 Win32 API FindFirstFile / FindNextFile / FindClose 函数。

以下 C++ 示例演示了 FindFirstFile 的最小使用。

#include <windows.h>
#include <tchar.h>
#include <stdio.h>

void _tmain(int argc, TCHAR *argv[])
{
   WIN32_FIND_DATA FindFileData;
   HANDLE hFind;

   if( argc != 2 )
   {
      _tprintf(TEXT("Usage: %s [target_file]\n"), argv[0]);
      return;
   }

   _tprintf (TEXT("Target file is %s\n"), argv[1]);
   hFind = FindFirstFile(argv[1], &FindFileData);
   if (hFind == INVALID_HANDLE_VALUE) 
   {
      printf ("FindFirstFile failed (%d)\n", GetLastError());
      return;
   } 
   else 
   {
      _tprintf (TEXT("The first file found is %s\n"), 
                FindFileData.cFileName);
      FindClose(hFind);
   }
}

源代码来自上述 msdn 页面。

评论

1赞 Константин Ван 8/11/2016
用法:FindFirstFile(TEXT("D:\\IMAGE\\MYDIRECTORY\\*"), &findFileData);
10赞 Roi Danton 4/13/2017
使用 C++ 14 时有 ,使用 C++17 时,它们具有与 boost 类似的功能(库派生自 boost)。请参阅下面 Shreevardhan 的答案。std::experimental::filesystemstd::filesystem
0赞 FindOutIslamNow 11/12/2018
有关详细信息,请参阅 learn.microsoft.com/en-us/windows/desktop/FileIO/...
1093赞 Peter Parker 3/5/2009 #3

2017年更新

在 C++17 中,现在有一种官方方法可以列出文件系统的文件:.下面有来自 Shreevardhan 的一个很好的答案,其中包含此源代码:std::filesystem

#include <string>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    std::string path = "/path/to/directory";
    for (const auto & entry : fs::directory_iterator(path))
        std::cout << entry.path() << std::endl;
}

旧答案:

在小而简单的任务中,我不使用 boost,我使用 .它在 UNIX 中作为标准标头提供,也可以通过 Toni Rönkkö 创建的兼容层用于 Windows。dirent.h

DIR *dir;
struct dirent *ent;
if ((dir = opendir ("c:\\src\\")) != NULL) {
  /* print all the files and directories within directory */
  while ((ent = readdir (dir)) != NULL) {
    printf ("%s\n", ent->d_name);
  }
  closedir (dir);
} else {
  /* could not open directory */
  perror ("");
  return EXIT_FAILURE;
}

它只是一个小的头文件,可以完成您需要的大部分简单事情,而无需使用基于模板的大型方法,例如 boost(没有冒犯,我喜欢 boost!

评论

8赞 Peter Parker 5/21/2013
@ArtOfWarfare:当这个问题被回答时,tinydir甚至没有被创建。此外,它是 dirent (POSIX) 和 FindFirstFile (Windows) 的包装器,而 dirent.h 只是包装 Windows 的 dirent。我认为这是个人品味,但 dirent.h 感觉更像是一种标准
9赞 Peter Parker 9/25/2014
@JoshC:因为 *ent 只是内部表示的返回指针。通过关闭目录,您也将消除 *ent。由于 *ent 仅用于阅读,我认为这是一个明智的设计。
63赞 Peter Parker 4/15/2016
人们变得真实!!这是 2009 年的问题,甚至没有提到 VS。因此,不要批评您的完全专有(尽管相当不错)IDE不支持数百年前的操作系统标准。我的回答还说它“可用”用于 Windows,从现在开始和所有时间都不会“包含”在任何 IDE 中......我很确定您可以下载 dirent 并将其放入一些包括 dir 中,瞧,它就在那里。
8赞 rustyx 7/4/2016
答案具有误导性。它应该以:“......我使用 dirent.h,它也存在 Windows 开源兼容层”。
17赞 Roi Danton 4/13/2017
使用 C++ 14 有 ,有 C++ 17 有 。请参阅下面 Shreevardhan 的答案。因此,不需要第三方库。std::experimental::filesystemstd::filesystem
9赞 robertvarga 4/9/2011 #4

查看使用 win32 api 的此类。只需通过提供所需的列表来构造一个实例,然后调用该方法从目录中获取下一个实例。我认为它需要和.foldernamegetNextFilefilenamewindows.hstdio.h

class FileGetter{
    WIN32_FIND_DATAA found; 
    HANDLE hfind;
    char folderstar[255];       
    int chk;

public:
    FileGetter(char* folder){       
        sprintf(folderstar,"%s\\*.*",folder);
        hfind = FindFirstFileA(folderstar,&found);
        //skip .
        FindNextFileA(hfind,&found);        
    }

    int getNextFile(char* fname){
        //skips .. when called for the first time
        chk=FindNextFileA(hfind,&found);
        if (chk)
            strcpy(fname, found.cFileName);     
        return chk;
    }

};

评论

0赞 Mayur 10/23/2020
您将在哪里关闭句柄?
4赞 Yas 2/20/2012 #5

我希望这段代码对你有帮助。

#include <windows.h>
#include <iostream>
#include <string>
#include <vector>
using namespace std;

string wchar_t2string(const wchar_t *wchar)
{
    string str = "";
    int index = 0;
    while(wchar[index] != 0)
    {
        str += (char)wchar[index];
        ++index;
    }
    return str;
}

wchar_t *string2wchar_t(const string &str)
{
    wchar_t wchar[260];
    int index = 0;
    while(index < str.size())
    {
        wchar[index] = (wchar_t)str[index];
        ++index;
    }
    wchar[index] = 0;
    return wchar;
}

vector<string> listFilesInDirectory(string directoryName)
{
    WIN32_FIND_DATA FindFileData;
    wchar_t * FileName = string2wchar_t(directoryName);
    HANDLE hFind = FindFirstFile(FileName, &FindFileData);

    vector<string> listFileNames;
    listFileNames.push_back(wchar_t2string(FindFileData.cFileName));

    while (FindNextFile(hFind, &FindFileData))
        listFileNames.push_back(wchar_t2string(FindFileData.cFileName));

    return listFileNames;
}

void main()
{
    vector<string> listFiles;
    listFiles = listFilesInDirectory("C:\\*.txt");
    for each (string str in listFiles)
        cout << str << endl;
}

评论

4赞 Daniel Kamil Kozar 10/23/2013
-1. 返回局部变量的地址。此外,您可能应该使用 WinAPI 中可用的转换方法,而不是编写自己的转换方法。string2wchar_t
4赞 JasonYen2205 3/30/2012 #6
char **getKeys(char *data_dir, char* tablename, int *num_keys)
{
    char** arr = malloc(MAX_RECORDS_PER_TABLE*sizeof(char*));
int i = 0;
for (;i < MAX_RECORDS_PER_TABLE; i++)
    arr[i] = malloc( (MAX_KEY_LEN+1) * sizeof(char) );  


char *buf = (char *)malloc( (MAX_KEY_LEN+1)*sizeof(char) );
snprintf(buf, MAX_KEY_LEN+1, "%s/%s", data_dir, tablename);

DIR* tableDir = opendir(buf);
struct dirent* getInfo;

readdir(tableDir); // ignore '.'
readdir(tableDir); // ignore '..'

i = 0;
while(1)
{


    getInfo = readdir(tableDir);
    if (getInfo == 0)
        break;
    strcpy(arr[i++], getInfo->d_name);
}
*(num_keys) = i;
return arr;
}
6赞 Homer6 11/12/2012 #7

GNU 手册 FTW

http://www.gnu.org/software/libc/manual/html_node/Simple-Directory-Lister.html#Simple-Directory-Lister

此外,有时直接找到源头(双关语)是件好事。通过查看 Linux 中一些最常见命令的内部结构,您可以学到很多东西。我在 github 上设置了 GNU 的 coreutils 的简单镜像(用于阅读)。

https://github.com/homer6/gnu_coreutils/blob/master/src/ls.c

也许这并不能解决 Windows,但通过使用这些方法可以解决许多使用 Unix 变体的情况。

希望能有所帮助...

61赞 congusbongus 2/4/2013 #8

对于仅限 C 的解决方案,请查看此内容。它只需要一个额外的标头:

https://github.com/cxong/tinydir

tinydir_dir dir;
tinydir_open(&dir, "/path/to/dir");

while (dir.has_next)
{
    tinydir_file file;
    tinydir_readfile(&dir, &file);

    printf("%s", file.name);
    if (file.is_dir)
    {
        printf("/");
    }
    printf("\n");

    tinydir_next(&dir);
}

tinydir_close(&dir);

与其他选项相比,一些优势:

  • 它是可移植的 - 包装 POSIX dirent 和 Windows FindFirstFile
  • 它在可用的地方使用,这意味着它(通常)是线程安全的readdir_r
  • 通过相同的宏支持 Windows UTF-16UNICODE
  • 它是 C90,所以即使是非常古老的编译器也可以使用它

评论

2赞 ArtOfWarfare 5/19/2013
非常好的建议。我还没有在 Windows 计算机上测试过它,但它在 OS X 上运行得非常出色。
0赞 Stepan Yakovenko 10/18/2017
该库不支持 std::string,因此您不能将 file.c_str() 传递给tinydir_open。在这种情况下,它在 msvc 2015 上编译期间出现错误 C2664。
0赞 9/3/2021
@StepanYakovenko作者明确表示“仅针对 C 解决方案”
32赞 Shrikant 10/23/2013 #9

我认为,下面的代码片段可用于列出所有文件。

#include <stdio.h>
#include <dirent.h>
#include <sys/types.h>

int main(int argc, char** argv) { 
    list_dir("myFolderName");
    return EXIT_SUCCESS;
}  

static void list_dir(const char *path) {
    struct dirent *entry;
    DIR *dir = opendir(path);
    if (dir == NULL) {
        return;
    }

    while ((entry = readdir(dir)) != NULL) {
        printf("%s\n",entry->d_name);
    }

    closedir(dir);
}

这是使用的结构(存在于):dirent.h

struct dirent {
    ino_t d_ino; /* inode number */
    off_t d_off; /* offset to the next dirent */
    unsigned short d_reclen; /* length of this record */
    unsigned char d_type; /* type of file */
    char d_name[256]; /* filename */
};

评论

0赞 selfboot 4/28/2019
我想要这个。
0赞 Nav 12/13/2020
这在 C++11 中为我完成了工作,而无需使用 Boost 等。 好解决方案!
0赞 KansaiRobot 5/27/2021
这真是太好了!我应该按什么顺序获取文件?
106赞 herohuyongtao 12/31/2013 #10

一个函数就足够了,您不需要使用任何第三方库(适用于 Windows)。

#include <Windows.h>

vector<string> get_all_files_names_within_folder(string folder)
{
    vector<string> names;
    string search_path = folder + "/*.*";
    WIN32_FIND_DATA fd; 
    HANDLE hFind = ::FindFirstFile(search_path.c_str(), &fd); 
    if(hFind != INVALID_HANDLE_VALUE) { 
        do { 
            // read all (real) files in current folder
            // , delete '!' read other 2 default folder . and ..
            if(! (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
                names.push_back(fd.cFileName);
            }
        }while(::FindNextFile(hFind, &fd)); 
        ::FindClose(hFind); 
    } 
    return names;
}

PS:如@Sebastian所述,您可以更改为仅获取该目录中的EXT文件(即特定类型的文件)。*.**.ext

评论

27赞 kraxor 5/29/2014
此解决方案如果特定于平台。这就是您需要第三方库的原因。
12赞 herohuyongtao 5/29/2014
@kraxor 是的,它只适用于 Windows,但 OP 从不要求拥有跨平台解决方案。顺便说一句,我总是喜欢在不使用第 3 个库的情况下选择一些东西(如果可能的话)。
10赞 kraxor 5/30/2014
@herohuyongtao OP 从未指定过平台,对一个通用问题给出一个严重依赖平台的解决方案可能会产生误导。(如果有仅适用于 PlayStation 3 的单行解决方案怎么办?这是一个很好的答案吗?我看到你编辑了你的答案,说它只适用于 Windows,我想这样很好。
3赞 Thomas 9/19/2014
@herohuyongtao OP 提到他无法解析 ls,这意味着他可能在 unix 上。无论如何,Windows的好答案。
3赞 PerryC 7/12/2016
我最终使用了 和 然后代替了字符串向量,这不会编译。std::vector<std::wstring>fileName.c_str()
25赞 Meekohi 2/11/2014 #11

为什么不使用 ?glob()

#include <glob.h>

glob_t glob_result;
glob("/your_directory/*",GLOB_TILDE,NULL,&glob_result);
for(unsigned int i=0; i<glob_result.gl_pathc; ++i){
  cout << glob_result.gl_pathv[i] << endl;
}

评论

0赞 Volomike 5/15/2016
如果您解释所需的包含,这可能是一个更好的答案。
2赞 orbitcowboy 5/21/2016
测试 glob() 是否返回零!
0赞 Kemin Zhou 7/22/2016
当您知道要查找的文件(例如 *.txt
1赞 Catalyst 7/3/2014 #12

系统调用它!

system( "dir /b /s /a-d * > file_names.txt" );

然后只需读取文件即可。

编辑:这个答案应该被认为是一个黑客,但如果你无法获得更优雅的解决方案,它确实有效(尽管是以特定于平台的方式)。

评论

7赞 yyny 4/26/2015
我不被允许执行“ls”命令并从我的程序中解析结果。我知道会有人发送这样的东西......
0赞 Chef Gladiator 12/2/2020
对于 Windows,这是迄今为止最实用的方式。特别注意开关。无论您选择哪种方式,安全性都可以在这里严重阻碍。如果一个人没有从一开始就“编码”。Windows 模拟、身份验证和其他“沙漠”从来都不是一件容易的事。/A
36赞 Chris Redford 7/12/2014 #13

我建议与这个可重复使用的包装器一起使用。它生成一个与符合 glob 模式的文件路径相对应的文件路径:globvector<string>

#include <glob.h>
#include <vector>
using std::vector;

vector<string> globVector(const string& pattern){
    glob_t glob_result;
    glob(pattern.c_str(),GLOB_TILDE,NULL,&glob_result);
    vector<string> files;
    for(unsigned int i=0;i<glob_result.gl_pathc;++i){
        files.push_back(string(glob_result.gl_pathv[i]));
    }
    globfree(&glob_result);
    return files;
}

然后可以使用正常的系统通配符模式调用它,例如:

vector<string> files = globVector("./*");

评论

2赞 Camille Goudeseune 5/22/2015
测试 glob() 是否返回零。
0赞 Tofuw 2/23/2016
我想按照您的建议使用 glob.h。但是,我仍然不能包含.h文件:它说.你能告诉我如何解决这个问题吗?No such file or directory
0赞 Volomike 5/16/2016
请注意,此例程仅深入一层(无递归)。它也不会进行快速检查以确定它是文件还是目录,您可以通过切换然后检查以斜杠结尾的路径来轻松完成。如果需要,您必须对其进行任何修改。GLOB_TILDEGLOB_TILDE | GLOB_MARK
0赞 Nikhil Augustine 7/1/2018
这是跨平台兼容的吗?
0赞 Alex Aparin 10/5/2018
不幸的是,您无法通过 找到统一隐藏的文件。glob
3赞 Giacomo Marciani 9/13/2014 #14

此实现实现了您的目的,即使用指定目录的内容动态填充字符串数组。

int exploreDirectory(const char *dirpath, char ***list, int *numItems) {
    struct dirent **direntList;
    int i;
    errno = 0;

    if ((*numItems = scandir(dirpath, &direntList, NULL, alphasort)) == -1)
        return errno;

    if (!((*list) = malloc(sizeof(char *) * (*numItems)))) {
        fprintf(stderr, "Error in list allocation for file list: dirpath=%s.\n", dirpath);
        exit(EXIT_FAILURE);
    }

    for (i = 0; i < *numItems; i++) {
        (*list)[i] = stringDuplication(direntList[i]->d_name);
    }

    for (i = 0; i < *numItems; i++) {
        free(direntList[i]);
    }

    free(direntList);

    return 0;
}

评论

0赞 Hal T 2/21/2017
我怎么称呼它?当我尝试在第一个块上运行此函数时,我遇到了段错误。我用ifchar **list; int numItems; exploreDirectory("/folder",list, numItems);
26赞 Bad 6/26/2015 #15

下面是一个非常简单的代码,使用库来获取目录中的文件名(不包括文件夹名称):C++11boost::filesystem

#include <string>
#include <iostream>
#include <boost/filesystem.hpp>
using namespace std;
using namespace boost::filesystem;

int main()
{
    path p("D:/AnyFolder");
    for (auto i = directory_iterator(p); i != directory_iterator(); i++)
    {
        if (!is_directory(i->path())) //we eliminate directories
        {
            cout << i->path().filename().string() << endl;
        }
        else
            continue;
    }
}

输出如下:

file1.txt
file2.dat

评论

0赞 Alexander Leon VI 7/9/2015
嗨,我在哪里可以得到这个库?
2赞 Bad 7/9/2015
@Alexander De Leon:你可以在他们的网站上 boost.org 获得这个库,先阅读入门指南,然后使用他们的库 boost.org/doc/libs/1_58_0/libs/filesystem/doc/index.htmboost::filesystem
0赞 Areeb Muzaffar 4/20/2021
@Bad我将如何更改它以输出每个文件的完整目录。比如我想要 D:/AnyFolder/file1.txt 等等?
514赞 Shreevardhan 5/28/2016 #16

C++17 现在有一个 std::filesystem::d irectory_iterator,可以用作

#include <string>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
 
int main() {
  std::string path = "/path/to/directory";

  for (const auto & entry : fs::directory_iterator(path)) {
    std::cout << entry.path() << std::endl;
  }
}

此外,std::filesystem::recursive_directory_iterator 也可以迭代子目录。

评论

41赞 PeterK 7/11/2016
AFAIK 也可以在 C++14 中使用,但它仍处于实验阶段:.不过它似乎工作正常。namespace fs = std::experimental::filesystem;
10赞 green diod 1/4/2017
这应该是当前使用的首选答案(从 C++17 开始)
5赞 Roi Danton 4/13/2017
传递 时注意 ,引号包含在输出中。为避免这种情况,请追加到路径以执行显式而不是隐式转换(此处)。示例:coliru.stacked-crooked.com/view?id=a55ea60bbd36a8a3std::filesystem::pathstd::cout.string()std::cout << p.string() << std::endl;
2赞 Snackoverflow 1/19/2018
文件名中的非 ASCII 字符呢?不应该使用或迭代器中的类型是什么?std::wstring
5赞 swalog 7/2/2019
我不确定我是否独自一人,但如果不链接到 ,我会得到一个 .我在文档中找不到任何需要这样做的地方,链接器也没有提供任何线索。这对两者都有效。有没有人对文档/规范中指定这样的事情有任何见解?-lstdc++fsSIGSEGV (Address boundary error)g++ 8.3.0clang 8.0.0-3
2赞 ENHering 5/22/2017 #17

这对我有用。如果我不记得来源,我很抱歉。它可能来自手册页。

#include <ftw.h>

int AnalizeDirectoryElement (const char *fpath, 
                            const struct stat *sb,
                            int tflag, 
                            struct FTW *ftwbuf) {

  if (tflag == FTW_F) {
    std::string strFileName(fpath);

    DoSomethingWith(strFileName);
  }
  return 0; 
}

void WalkDirectoryTree (const char * pchFileName) {

  int nFlags = 0;

  if (nftw(pchFileName, AnalizeDirectoryElement, 20, nFlags) == -1) {
    perror("nftw");
  }
}

int main() {
  WalkDirectoryTree("some_dir/");
}
6赞 Venkat Vinay 3/13/2018 #18

Shreevardhan的答案很好用。但是如果你想在 c++14 中使用它,只需进行更改即可namespace fs = experimental::filesystem;

即,

#include <string>
#include <iostream>
#include <filesystem>

using namespace std;
namespace fs = experimental::filesystem;

int main()
{
    string path = "C:\\splits\\";
    for (auto & p : fs::directory_iterator(path))
        cout << p << endl;
    int n;
    cin >> n;
}
1赞 tkingcer 4/10/2018 #19

由于目录的文件和子目录通常以树状结构存储,因此直观的方法是使用 DFS 算法递归遍历每个文件和子目录。 下面是 Windows 操作系统中使用 io.h 中的基本文件函数的示例。您可以在其他平台中替换这些功能。我想表达的是,DFS的基本思想完美地解决了这个问题。

#include<io.h>
#include<iostream.h>
#include<string>
using namespace std;

void TraverseFilesUsingDFS(const string& folder_path){
   _finddata_t file_info;
   string any_file_pattern = folder_path + "\\*";
   intptr_t handle = _findfirst(any_file_pattern.c_str(),&file_info);
   //If folder_path exsist, using any_file_pattern will find at least two files "." and "..", 
   //of which "." means current dir and ".." means parent dir
   if (handle == -1){
       cerr << "folder path not exist: " << folder_path << endl;
       exit(-1);
   }
   //iteratively check each file or sub_directory in current folder
   do{
       string file_name=file_info.name; //from char array to string
       //check whtether it is a sub direcotry or a file
       if (file_info.attrib & _A_SUBDIR){
            if (file_name != "." && file_name != ".."){
               string sub_folder_path = folder_path + "\\" + file_name;                
               TraverseFilesUsingDFS(sub_folder_path);
               cout << "a sub_folder path: " << sub_folder_path << endl;
            }
       }
       else
            cout << "file name: " << file_name << endl;
    } while (_findnext(handle, &file_info) == 0);
    //
    _findclose(handle);
}
2赞 ducPham 4/21/2018 #20

您可以使用 std::experimental:: filesystem::d irectory_iterator() 获取根目录中的所有直接文件。然后,读取这些路径文件的名称。

#include <iostream>
#include <filesystem>
#include <string>
#include <direct.h>
using namespace std;
namespace fs = std::experimental::filesystem;
void ShowListFile(string path)
{
for(auto &p: fs::directory_iterator(path))  /*get directory */
     cout<<p.path().filename()<<endl;   // get file name
}

int main() {

ShowListFile("C:/Users/dell/Pictures/Camera Roll/");
getchar();
return 0;
}
2赞 ZKR 9/4/2018 #21

此答案应该适用于无法将 Visual Studio 与任何其他答案一起使用的 Windows 用户。

  1. 从 github 页面下载 dirent.h 文件。但最好只使用 Raw dirent.h 文件并按照我的以下步骤操作(这就是我让它工作的方式)。

    dirent.h for Windows 的 Github 页面: dirent.h 的 Github 页面

    原始 dirent 文件:原始 dirent.h 文件

  2. 转到您的项目并添加新项 (++)。添加头文件 (.h) 并将其命名为 dirent.h。CtrlShiftA

  3. Raw dirent.h 文件代码粘贴到标头中。

  4. 在代码中包含“dirent.h”。

  5. 将以下方法放入代码中,然后从函数中调用它,或者编辑函数以使其使用。void filefinder()main

    #include <stdio.h>
    #include <string.h>
    #include "dirent.h"
    
    string path = "C:/folder"; //Put a valid path here for folder
    
    void filefinder()
    {
        DIR *directory = opendir(path.c_str());
        struct dirent *direntStruct;
    
        if (directory != NULL) {
            while (direntStruct = readdir(directory)) {
                printf("File Name: %s\n", direntStruct->d_name); //If you are using <stdio.h>
                //std::cout << direntStruct->d_name << std::endl; //If you are using <iostream>
            }
        }
        closedir(directory);
    }
    
2赞 OpticalMagician 9/25/2018 #22

我试图遵循两个答案中给出的示例,可能值得注意的是,它似乎已被更改为没有运算符的过载。相反,我必须使用以下内容才能编译并使其正常工作:std::filesystem::directory_entry<<std::cout << p << std::endl;

#include <iostream>
#include <filesystem>
#include <string>
namespace fs = std::filesystem;

int main() {
    std::string path = "/path/to/directory";
    for(const auto& p : fs::directory_iterator(path))
        std::cout << p.path() << std::endl;
}

尝试自行传递导致丢失的重载错误。pstd::cout <<

0赞 Kevin Ng 9/29/2018 #23

只是我想分享的东西,并感谢您的阅读材料。玩一玩这个函数来理解它。你可能会喜欢它。e 代表扩展,p 代表路径,s 代表路径分隔符。

如果路径传递时没有结束分隔符,则会在路径上附加一个分隔符。对于扩展名,如果输入空字符串,则该函数将返回名称中没有扩展名的任何文件。如果输入了单个星号,则将返回目录中的所有文件。如果 e 长度大于 0 但不是单个 *,则如果 e 在零位置没有包含点,则将在 e 前面附加一个点。

对于返回值。如果返回零长度映射,则未找到任何内容,但目录已打开。如果返回值中提供了索引 999,但地图大小仅为 1,则意味着打开目录路径时存在问题。

请注意,为了提高效率,此功能可以拆分为 3 个较小的函数。最重要的是,您可以创建一个调用方函数,该函数将根据输入检测要调用的函数。为什么这样更有效率?也就是说,如果您要抓取所有文件,则执行该方法,为抓取所有文件而构建的子函数将只抓取所有文件,并且不需要在每次找到文件时评估任何其他不必要的条件。

这也适用于抓取没有扩展名的文件时。用于此目的的特定构建函数只会评估是否找到的对象是文件,然后评估文件名中是否包含点。

如果您只读取文件不多的目录,则节省的时间可能不会太多。但是,如果您正在读取大量目录,或者该目录有几十万个文件,则可以节省大量资金。

#include <stdio.h>
#include <sys/stat.h>
#include <iostream>
#include <dirent.h>
#include <map>

std::map<int, std::string> getFile(std::string p, std::string e = "", unsigned char s = '/'){
    if ( p.size() > 0 ){
        if (p.back() != s) p += s;
    }
    if ( e.size() > 0 ){
        if ( e.at(0) != '.' && !(e.size() == 1 && e.at(0) == '*') ) e = "." + e;
    }

    DIR *dir;
    struct dirent *ent;
    struct stat sb;
    std::map<int, std::string> r = {{999, "FAILED"}};
    std::string temp;
    int f = 0;
    bool fd;

    if ( (dir = opendir(p.c_str())) != NULL ){
        r.erase (999);
        while ((ent = readdir (dir)) != NULL){
            temp = ent->d_name;
            fd = temp.find(".") != std::string::npos? true : false;
            temp = p + temp;

            if (stat(temp.c_str(), &sb) == 0 && S_ISREG(sb.st_mode)){
                if ( e.size() == 1 && e.at(0) == '*' ){
                    r[f] = temp;
                    f++;
                } else {
                    if (e.size() == 0){
                        if ( fd == false ){
                            r[f] = temp;
                            f++;
                        }
                        continue;
                    }

                    if (e.size() > temp.size()) continue;

                    if ( temp.substr(temp.size() - e.size()) == e ){
                        r[f] = temp;
                        f++;
                    }
                }
            }
        }

        closedir(dir);
        return r;
    } else {
        return r;
    }
}

void printMap(auto &m){
    for (const auto &p : m) {
        std::cout << "m[" << p.first << "] = " << p.second << std::endl;
    }
}

int main(){
    std::map<int, std::string> k = getFile("./", "");
    printMap(k);
    return 0;
}
1赞 tzg 8/30/2019 #24

在 herohuyongtao 发布的内容和其他一些帖子的基础上:

http://www.cplusplus.com/forum/general/39766/

FindFirstFile 的预期输入类型是什么?

如何把wstring转换成string?

这是一个 Windows 解决方案。

由于我想传入 std::string 并返回字符串向量,因此我不得不进行几次转换。

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

std::vector<std::string> listFilesInDir(std::string path)
{
    std::vector<std::string> names;
    //Convert string to wstring
    std::wstring search_path = std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes(path);
    WIN32_FIND_DATA fd;
    HANDLE hFind = FindFirstFile(search_path.c_str(), &fd);
    if (hFind != INVALID_HANDLE_VALUE) 
    {
        do 
        {
            // read all (real) files in current folder
            // , delete '!' read other 2 default folder . and ..
            if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) 
            {
                //convert from wide char to narrow char array
                char ch[260];
                char DefChar = ' ';
                WideCharToMultiByte(CP_ACP, 0, fd.cFileName, -1, ch, 260, &DefChar, NULL);
                names.push_back(ch);
            }
        } 
        while (::FindNextFile(hFind, &fd));
        ::FindClose(hFind);
    }
    return names;
}

评论

1赞 Kiran Thilak 12/6/2019
如果您知道您将只使用多字节,则可以使用 和 。那么就不需要将结果转换为多字节或将输入转换为unicode。WIN32_FIND_DATAAFindFirstFileAFindNextFileA
0赞 Chef Gladiator 12/2/2020
只是建议:已弃用(几年前)。如果你用某种英语使用操作系统,也许这可能是一个足够好的替代品,..除了字符串的向量之外,我认为使用c++异常是获得最大和最慢解决方案的可靠方法。除非您使用一些非常好的 std lib 替代品......std::wstring_convert
0赞 Stan Sokolov 12/10/2019 #25
#include<iostream>
#include <dirent.h>
using namespace std;
char ROOT[]={'.'};

void listfiles(char* path){
    DIR * dirp = opendir(path);
    dirent * dp;
    while ( (dp = readdir(dirp)) !=NULL ) {
         cout << dp->d_name << " size " << dp->d_reclen<<std::endl;
    }
    (void)closedir(dirp);
}

int main(int argc, char **argv)
{
    char* path;
    if (argc>1) path=argv[1]; else path=ROOT;

    cout<<"list files in ["<<path<<"]"<<std::endl;
    listfiles(path);

    return 0;
}
1赞 Burak 1/13/2021 #26

基于以上答案

#include <vector>
#include <string>
#include <algorithm>

#ifdef _WIN32
#include <windows.h>
std::vector<std::string> files_in_directory(std::string path)
{
    std::vector<std::string> files;

    // check directory exists
    char fullpath[MAX_PATH];
    GetFullPathName(path.c_str(), MAX_PATH, fullpath, 0);
    std::string fp(fullpath);
    if (GetFileAttributes(fp.c_str()) != FILE_ATTRIBUTE_DIRECTORY)
        return files;

    // get file names
    WIN32_FIND_DATA findfiledata;
    HANDLE hFind = FindFirstFile((LPCSTR)(fp + "\\*").c_str(), &findfiledata);
    if (hFind != INVALID_HANDLE_VALUE)
    {
        do 
        {
            files.push_back(findfiledata.cFileName);
        } 
        while (FindNextFile(hFind, &findfiledata));
        FindClose(hFind);
    }

    // delete current and parent directories
    files.erase(std::find(files.begin(), files.end(), "."));
    files.erase(std::find(files.begin(), files.end(), ".."));

    // sort in alphabetical order
    std::sort(files.begin(), files.end());

    return files;
}
#else
#include <dirent.h>
std::vector<std::string> files_in_directory(std::string directory)
{
    std::vector<std::string> files;

    // open directory
    DIR *dir;
    dir = opendir(directory.c_str());
    if (dir == NULL)
        return files;

    // get file names
    struct dirent *ent;
    while ((ent = readdir(dir)) != NULL)
        files.push_back(ent->d_name);
    closedir(dir);

    // delete current and parent directories
    files.erase(std::find(files.begin(), files.end(), "."));
    files.erase(std::find(files.begin(), files.end(), ".."));

    // sort in alphabetical order
    std::sort(files.begin(), files.end());

    return files;
}
#endif  // _WIN32

评论

0赞 0xC0000022L 9/22/2021
对于 C++17,我们应该使用和类似。std::filesystem::directory_iterator
0赞 Burak 9/22/2021
@0xC0000022L当然。这是一个跨平台的解决方案,适用于不支持 c++17 的用户。
0赞 0xC0000022L 9/22/2021
这几乎不是跨平台的。Windows 实现本身不考虑被定义。此外,在面对非常大的目录中的用户时,这将爆炸。为什么大多数(底层)API 已经基于迭代器模型,而不是一次获取一个巨大的列表,这是有原因的。也就是说,这当然是一个开始。但坦率地说,我可能会重写 Windows 部分以表现得像朋友,因为这意味着一个比您提供的界面更灵活的界面。_UNICODEreaddir()
1赞 Burak 9/23/2021
@0xC0000022L 感谢您的反馈。我在文件不多的小项目中使用了这段代码,平台是 Windows 或 Ubuntu。这些代码不属于我。(我应该参考消息来源。对于大多数情况来说,这是一个简单的解决方案。我发布了这个供以后参考并与其他人分享。由于 C++17 现在被广泛使用,这篇文章不再需要。但是,如果您认为保留没有第三方库的非现代解决方案是个好主意,我建议您发布一个新答案,在这种情况下,我将删除此答案。
6赞 3ashry 1/14/2021 #27
#include <string>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main() {
    std::string path = "/path/to/directory";
    for (const auto & entry : fs::directory_iterator(path))
        std::cout << entry.path() << std::endl;
}
2赞 jarikmesik 11/16/2021 #28

Shreevardhan 的设计也非常适合遍历子目录:

#include <string>
#include <iostream>
#include <filesystem>

using namespace std;
namespace fs = filesystem;
int main()
{
    string path = "\\path\\to\\directory";
    // string path = "/path/to/directory";
    for (auto & p : fs::recursive_directory_iterator(path))
        cout << p.path() << endl;
}

汇编:cl /EHsc /W4 /WX /std:c++17 ListFiles.cpp

1赞 Vaibhav Pallod 7/19/2022 #29

只需在 Linux 中使用以下 ASCI C 样式代码即可

#include <bits/stdc++.h>
#include <dirent.h>
using namespace std;

int main(){
    DIR *dpdf;
    struct dirent *epdf;
    dpdf = opendir("./");
    
    if (dpdf != NULL){
    while (epdf = readdir(dpdf)){
        cout << epdf->d_name << std::endl;
    }
    }
    closedir(dpdf);
    return 0;
}

希望这有帮助!

2赞 Master Yoda 11/18/2022 #30

彼得·帕克(Peter Parker)的解决方案,但不用于:

#include <algorithm>
#include <filesystem>
#include <ranges>
#include <vector>

using namespace std;

int main() {
    vector<filesystem::path> filePaths;
    ranges::transform(filesystem::directory_iterator("."),     
    back_inserter(filePaths), [](const auto& dirFile){return dirFile.path();} );
}