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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/612097/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 16:15:20  来源:igfitidea点击:

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

c++cfiledirectory

提问by samoz

How can I determine the list of files in a directory from inside my C or C++ code?

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

I'm not allowed to execute the lscommand and parse the results from within my program.

我不允许ls在我的程序中执行命令和解析结果。

回答by Peter Parker

In small and simple tasks I do not use boost, I use dirent.hwhich is also available for windows:

在小而简单的任务中,我不使用 boost,我使用dirent.h,它也可用于 Windows:

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;
}

It is just a small header file and does most of the simple stuff you need without using a big template-based approach like boost(no offence, I like boost!).

它只是一个小的头文件,可以在不使用像 boost 这样的基于模板的大方法的情况下完成你需要的大部分简单的事情(没有冒犯,我喜欢 boost!)。

The author of the windows compatibility layer is Toni Ronkko. In Unix, it is a standard header.

windows兼容层的作者是Toni Ronkko。在 Unix 中,它是一个标准的头文件。

UPDATE 2017:

2017 年更新

In C++17 there is now an official way to list files of your file system: std::filesystem. There is an excellent answer from Shreevardhanbelow with this source code:

在 C++17 中,现在有一种正式的方法来列出文件系统的文件:std::filesystem. 下面是Shreevardhan 的一个很好的答案,带有这个源代码:

#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;
}

回答by Shreevardhan

C++17 now has a std::filesystem::directory_iterator, which can be used as

C++17 现在有一个std::filesystem::directory_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;
}

Also, std::filesystem::recursive_directory_iteratorcan iterate the subdirectories as well.

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

回答by Brian R. Bondy

Unfortunately the C++ standard does not define a standard way of working with files and folders in this way.

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

Since there is no cross platform way, the best cross platform way is to use a library such as the boost filesystem module.

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

Cross platform boost method:

跨平台提升方法:

The following function, given a directory path and a file name, recursively searches the directory and its sub-directories for the file name, returning a bool, and if successful, the path to the file that was found.

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;
}

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

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;
}

Source from the boost page mentioned above.

来自上述提升页面的来源。

For Unix/Linux based systems:

对于基于 Unix/Linux 的系统:

You can use opendir/ readdir/ closedir.

您可以使用opendir/ readdir/ closedir

Sample code which searches a directory for entry ``name'' is:

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;

在目录中搜索条目“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;

Source code from the above man pages.

来自上述手册页的源代码。

For a windows based systems:

对于基于 Windows 的系统:

You can use the Win32 API FindFirstFile/ FindNextFile/ FindClosefunctions.

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

The following C++ example shows you a minimal use of 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);
   }
}

以下 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);
   }
}

Source code from the above msdn pages.

来自上述 msdn 页面的源代码。

回答by herohuyongtao

One function is enough, you don't need to use any 3rd-party library (for Windows).

一个功能就足够了,您不需要使用任何 3rd 方库(适用于 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: as mentioned by @Sebastian, you could change *.*to *.extin order to get only the EXT-files (i.e. of a specific type) in that directory.

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

回答by congusbongus

For a C only solution, please check this out. It only requires an extra header:

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

https://github.com/cxong/tinydir

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);

Some advantages over other options:

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

  • It's portable - wraps POSIX dirent and Windows FindFirstFile
  • It uses readdir_rwhere available, which means it's (usually) threadsafe
  • Supports Windows UTF-16 via the same UNICODEmacros
  • It is C90 so even very ancient compilers can use it
  • 它是可移植的 - 包装了 POSIX dirent 和 Windows FindFirstFile
  • readdir_r在可用的地方使用,这意味着它(通常)是线程安全的
  • 通过相同的UNICODE宏支持 Windows UTF-16
  • 它是 C90 所以即使是非常古老的编译器也可以使用它

回答by Chris Redford

I recommend using globwith this reusable wrapper. It generates a vector<string>corresponding to file paths that fit the glob pattern:

我建议使用glob这个可重用的包装器。它生成一个vector<string>对应于适合 glob 模式的文件路径:

#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;
}

Which can then be called with a normal system wildcard pattern such as:

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

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

回答by Meekohi

Why not use glob()?

为什么不使用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;
}

回答by Bad

Here is a very simple code in C++11using boost::filesystemlibrary to get file names in a directory (excluding folder names):

这是C++11使用boost::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;
    }
}

Output is like:

输出是这样的:

file1.txt
file2.dat

回答by Shrikant

I think, below snippet can be used to list all the files.

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

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

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);
}

Following is the structure of the struct dirent

以下是struct dirent的结构

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 */
};

回答by Tim

Try boost for x-platform method

尝试提升 x 平台方法

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

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

or just use your OS specific file stuff.

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