我们如何在标准C ++中递归地遍历每个文件/目录?
我们如何在标准C ++中递归地遍历每个文件/目录?
解决方案
回答
我们需要调用操作系统特定的函数来进行文件系统遍历,例如" open()"和" readdir()"。 C标准未指定任何与文件系统相关的功能。
回答
我们可能需要检查boost.filesystem
http://www.boost.org/doc/libs/1_31_0/libs/filesystem/doc/index.htm
回答
在标准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; }
回答
你不知道标准C ++没有公开目录的概念。具体来说,它无法列出目录中的所有文件。
一个可怕的办法是使用system()调用并解析结果。最合理的解决方案是使用某种跨平台库,例如Qt甚至POSIX。
回答
如果使用Win32 API,则可以使用FindFirstFile和FindNextFile函数。
http://msdn.microsoft.com/zh-CN/library/aa365200(VS.85).aspx
对于目录的递归遍历,必须检查每个WIN32_FIND_DATA.dwFileAttributes,以检查是否设置了FILE_ATTRIBUTE_DIRECTORY位。如果该位置1,则可以在该目录中递归调用该函数。另外,我们可以使用堆栈来提供与递归调用相同的效果,但避免在很长的路径树上发生堆栈溢出。
#include <windows.h> #include <string> #include <vector> #include <stack> #include <iostream> using namespace std; bool ListFiles(wstring path, wstring mask, vector<wstring>& files) { HANDLE hFind = INVALID_HANDLE_VALUE; WIN32_FIND_DATA ffd; wstring spec; stack<wstring> 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<wstring> files; if (ListFiles(L"F:\cvsrepos", L"*", files)) { for (vector<wstring>::iterator it = files.begin(); it != files.end(); ++it) { wcout << it->c_str() << endl; } } return 0; }
回答
你不知道C ++标准没有目录的概念。将字符串转换为文件句柄取决于实现。该字符串的内容及其映射的内容取决于操作系统。请记住,C ++可用于编写该OS,因此它的使用级别尚未定义询问如何遍历目录的权限(因为我们正在编写目录管理代码)。
请查看OS API文档,以了解如何执行此操作。如果我们需要具有便携性,则必须为各种操作系统使用大量的#ifdefs。
回答
除了上面提到的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 <qapplication.h> #include <qdir.h> #include <iostream> 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; }