如何在标准C++中递归遍历每个文件/目录?
在标准C++中,从技术上讲,没有办法做到这一点,因为标准C++没有目录概念.如果你想稍微扩展你的网络,你可能想看看使用Boost.FileSystem.这已被接受包含在TR2中,因此这为您提供了尽可能接近标准的最佳实施机会.
一个例子,直接来自网站:
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; }
在带有"Filesystem TS"的C++
11/14中,标题和范围 - for
你可以简单地这样做:
#includeusing recursive_directory_iterator = std::filesystem::recursive_directory_iterator; ... for (const auto& dirEntry : recursive_directory_iterator(myPath)) std::cout << dirEntry << std::endl;
从C++ 17开始,它std::filesystem
是标准库的一部分,可以在
标题中找到(不再是"实验性的").
如果使用Win32 API,则可以使用FindFirstFile和FindNextFile函数.
http://msdn.microsoft.com/en-us/library/aa365200(VS.85).aspx
对于目录的递归遍历,您必须检查每个WIN32_FIND_DATA.dwFileAttributes以检查是否设置了FILE_ATTRIBUTE_DIRECTORY位.如果该位已设置,则可以递归调用该目录的函数.或者,您可以使用堆栈来提供递归调用的相同效果,但避免了很长路径树的堆栈溢出.
#include#include #include #include #include using namespace std; bool ListFiles(wstring path, wstring mask, vector & files) { HANDLE hFind = INVALID_HANDLE_VALUE; WIN32_FIND_DATA ffd; wstring spec; stack directories; directories.push(path); files.clear(); while (!directories.empty()) { path = directories.top(); spec = path + L"\\" + mask; directories.pop(); hFind = FindFirstFile(spec.c_str(), &ffd); if (hFind == INVALID_HANDLE_VALUE) { return false; } do { if (wcscmp(ffd.cFileName, L".") != 0 && wcscmp(ffd.cFileName, L"..") != 0) { if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { directories.push(path + L"\\" + ffd.cFileName); } else { files.push_back(path + L"\\" + ffd.cFileName); } } } while (FindNextFile(hFind, &ffd) != 0); if (GetLastError() != ERROR_NO_MORE_FILES) { FindClose(hFind); return false; } FindClose(hFind); hFind = INVALID_HANDLE_VALUE; } return true; } int main(int argc, char* argv[]) { vector files; if (ListFiles(L"F:\\cvsrepos", L"*", files)) { for (vector ::iterator it = files.begin(); it != files.end(); ++it) { wcout << it->c_str() << endl; } } return 0; }
使用新的基于C++ 11范围for
和Boost可以使它更简单:
#includeusing namespace boost::filesystem; struct recursive_directory_range { typedef recursive_directory_iterator iterator; recursive_directory_range(path p) : p_(p) {} iterator begin() { return recursive_directory_iterator(p_); } iterator end() { return recursive_directory_iterator(); } path p_; }; for (auto it : recursive_directory_range(dir_path)) { std::cout << it << std::endl; }
一个快速的解决方案是使用C的Dirent.h库.
来自维基百科的工作代码片段:
#include#include int listdir(const char *path) { struct dirent *entry; DIR *dp; dp = opendir(path); if (dp == NULL) { perror("opendir: Path does not exist or could not be read."); return -1; } while ((entry = readdir(dp))) puts(entry->d_name); closedir(dp); return 0; }
除了上面提到的boost :: filesystem之外,您可能还想检查wxWidgets :: wxDir和Qt :: QDir.
wxWidgets和Qt都是开源的跨平台C++框架.
wxDir
提供了一种使用Traverse()
简单GetAllFiles()
函数递归遍历文件的灵活方法.您也可以使用GetFirst()
和GetNext()
函数实现遍历(我假设Traverse()和GetAllFiles()是最终使用GetFirst()和GetNext()函数的包装器).
QDir
提供对目录结构及其内容的访问.有几种方法可以使用QDir遍历目录.您可以使用QDirIterator :: Subdirectories标志实例化的QDirIterator迭代目录内容(包括子目录).另一种方法是使用QDir的GetEntryList()函数并实现递归遍历.
下面是示例代码(取自这里展示了如何遍历所有子目录#例8-5).
#include#include #include int main( int argc, char **argv ) { QApplication a( argc, argv ); QDir currentDir = QDir::current(); currentDir.setFilter( QDir::Dirs ); QStringList entries = currentDir.entryList(); for( QStringList::ConstIterator entry=entries.begin(); entry!=entries.end(); ++entry) { std::cout << *entry << std::endl; } return 0; }
Boost :: filesystem提供了recursive_directory_iterator,这对于这个任务非常方便:
#include "boost/filesystem.hpp" #includeusing namespace boost::filesystem; recursive_directory_iterator end; for (recursive_directory_iterator it("./"); it != end; ++it) { std::cout << *it << std::endl; }
您可以使用ftw(3)
或nftw(3)
在POSIX系统上以C或C ++遍历文件系统层次结构。