如何从C或C++代码中确定目录中的文件列表?
我不允许执行ls
命令并从我的程序中解析结果.
在小而简单的任务中我不使用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; }
它只是一个小的头文件,可以完成你需要的大部分简单的东西,而不需要使用像boost这样的基于模板的大方法(没有冒犯,我喜欢boost!).
Windows兼容层的作者是Toni Ronkko.在Unix中,它是标准头.
2017年更新:
在C++ 17中,现在有一种列出文件系统文件的官方方法:std::filesystem
.下面的Shreevardhan有一个很好的答案,源代码如下:
#include#include #include 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; }
C++ 17现在有一个std::filesystem::directory_iterator
,可以用作
#include#include #include 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
还可以迭代子目录.
不幸的是,C++标准没有以这种方式定义使用文件和文件夹的标准方法.
由于没有跨平台方式,最好的跨平台方式是使用诸如boost文件系统模块之类的库.
跨平台提升方法:
给定目录路径和文件名的以下函数以递归方式在目录及其子目录中搜索文件名,返回bool,如果成功,则返回找到的文件的路径.
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#include #include 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页面的源代码.
一个功能就足够了,您不需要使用任何第三方库(适用于Windows).
#includevector get_all_files_names_within_folder(string folder) { vector 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文件(即特定类型).
对于仅限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
可用的地方,这意味着它(通常)线程安全
通过相同的UNICODE
宏支持Windows UTF-16
它是C90,所以即使非常古老的编译器也可以使用它
我建议使用glob
这个可重复使用的包装器.它生成一个vector
适合glob模式的文件路径:
#include#include using std::vector; vector globVector(const string& pattern){ glob_t glob_result; glob(pattern.c_str(),GLOB_TILDE,NULL,&glob_result); vector files; for(unsigned int i=0;i 然后可以使用正常的系统通配符模式调用,例如:
vectorfiles = globVector("./*");
测试glob()返回零.
7> Bad..:这是一个非常简单的代码,
C++11
使用boost::filesystem
库来获取目录中的文件名(文件夹名称除外):#include#include #include 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
@Alexander De Leon:您可以在他们的网站http://www.boost.org/上获取此库,首先阅读入门指南,然后使用他们的`boost :: filesystem`库http://www.boost.org/ DOC /库/ 1_58_0 /库/文件系统/ DOC/index.htm的
8> Meekohi..:为什么不用
glob()
?#includeglob_t glob_result; glob("/your_directory/*",GLOB_TILDE,NULL,&glob_result); for(unsigned int i=0; i
适用于C编程(在Mac OS X上测试过)!
测试glob()返回零!
9> Shrikant..:我想,下面的代码片段可用于列出所有文件.
#include#include #include 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); } 以下是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 */ };
10> Tim..:尝试使用x-platform方法进行提升
http://www.boost.org/doc/libs/1_38_0/libs/filesystem/doc/index.htm
或者只是使用您的操作系统特定文件.
11> 小智..:看看这个使用win32 api的类.只需通过提供
foldername
您想要列表的实例来构造实例,然后调用该getNextFile
方法filename
从目录中获取下一个实例.我认为它需要windows.h
和stdio.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; } };
12> Homer6..: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变体的情况.
希望有帮助......