我们如何在标准C ++中递归地遍历每个文件/目录?

时间:2020-03-05 18:54:37  来源:igfitidea点击:

我们如何在标准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;
}