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

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

我不能执行'ls'命令并从我的程序中parsing结果。

在小而简单的任务中,我不使用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这样的基于模板的大方法就可以完成大多数简单的工作(无需冒犯,我喜欢提升!)。

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

2017年更新

在C ++ 17中,现在有一个官方的方式来列出你的文件系统的文件: std::filesystem 。 下面是源代码Shreevardhan的一个很好的答案:

 #include <string> #include <iostream> #include <filesystem> namespace fs = std::filesystem; int main() { std::string path = "path_to_directory"; for (auto & p : fs::directory_iterator(path)) std::cout << p << std::endl; } 

如果您正在使用C ++ 17方法,请考虑加强他的答案。

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

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

跨平台升压方法:

以下函数给出一个目录path和一个文件名,recursion地search目录及其子目录中的文件名,返回一个bool,如果成功的话,findfind的文件的path。

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

来自上面提到的boost页面。


对于基于Unix / Linux的系统:

你可以使用opendir / readdir / closedir 。

search目录“`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页面。

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 (auto & p : fs::directory_iterator(path)) std::cout << p << std::endl; } 

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

一个function就足够了,您不需要使用任何第三方库(对于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文件(即特定types的文件)。

对于C唯一的解决scheme,请检查这一点。 它只需要一个额外的头文件:

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 ,这意味着它(通常)是线程安全的
  • 通过相同的UNICODEmacros支持Windows UTF-16
  • 这是C90,所以即使是非常古老的编译器也可以使用它

我build议使用glob与这个可重用的包装。 它将生成一个与文件path相对应的vector<string> ,该文件path符合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; } 

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

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

这里是一个非常简单的代码,在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; } } 

输出如下所示:

 file1.txt file2.dat 

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

我想,下面的代码片段可以用来列出所有的文件。

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

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

尝试提升x平台的方法

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

或者只使用你的操作系统特定的文件的东西

看看这个使用win32 api的类。 只需通过提供您想要列表的filename getNextFile foldername来构造一个实例,然后调用getNextFile方法从目录中获取下一个filename 。 我认为它需要windows.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; } }; 

GNU手册FTW

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

另外,有时去源头(双关语)是很好的。 您可以通过查看Linux中一些最常用命令的内部知识来了解更多。 我已经在github上build立了一个GNU coreutils的简单镜像(供阅读)。

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

也许这不能解决Windows的问题,但是使用这些方法可以使用许多使用Unix变体的例子。

希望有帮助…

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

系统调用它!

 system( "dir /b /s /ad * > file_names.txt" ); 

然后,只要阅读文件。

编辑:这个答案应该被认为是一个黑客,但如果你没有更优雅的解决scheme,它确实可以工作(尽pipe以平台特定的方式)。

我希望这个代码可以帮助你。

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

这个实现实现了你的目的,dynamic地填充指定目录的内容的string数组。

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

这对我有用。 如果我不记得来源,我很抱歉。 这可能是从一个手册页。

 #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/"); } 

这对我有效。 它只用所有文件的名称(无path)写一个文件。 然后它读取该txt文件并为您打印。

 void DisplayFolderContent() { system("dir /n /b * > file_names.txt"); char ch; std::fstream myStream("file_names.txt", std::fstream::in); while (myStream.get(ch)) { std::cout << ch; } }