tags:

views:

6552

answers:

7

How do you iterate through every file/directory recursively in standard C++

+1  A: 

You need to call OS-specific functions for filesystem traversal, like open() and readdir(). The C standard does not specify any filesystem-related functions.

John Millikin
What about C++? Are there any such functions in iostream?
Aaron Maenpaa
Only for files. There aren't any kind of "show me all the files in a directory" functions.
1800 INFORMATION
+4  A: 

You may want to examine boost.filesystem

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

Doug T.
+20  A: 

In standard C++, technically there is no way to do this since standard C++ has no conception of directories. If you want to expand your net a little bit, you might like to look at using Boost.FileSystem. This has been accepted for inclusion in TR2, so this gives you the best chance of keeping your implementation as close as possible to the standard.

An example, taken straight from the website:

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;
}
1800 INFORMATION
C++ has no concept of files? What about std::fstream? Or fopen?
Kevin
files, not directories
1800 INFORMATION
+1  A: 

You don't. standard C++ doesn't expose to concept of a directory. specifically it doesn't give any way to list all the files in a directory. A horrible hack would be to use system() calls and to parse the results. The most reasonable solution would be to use some kind of cross platform library such as QT or even posix.

shoosh
+12  A: 

If using the Win32 API you can use the FindFirstFile and FindNextFile functions.

http://msdn.microsoft.com/en-us/library/aa365200(VS.85).aspx

For recursive traversal of directories you must inspect each WIN32_FIND_DATA.dwFileAttributes to check if the FILE_ATTRIBUTE_DIRECTORY bit is set. If the bit is set then you can recursively call the function with that directory. Alternatively you can use a stack for providing the same effect of a recursive call but avoiding stack overflow for very long path trees.

#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;
}
smink
how long did it take you to write that? I think it would take less time to glue C++ to python and do it in one line.
Dustin Getz
This is a nice, non-recursive solution (which is sometimes handy!).
jm
+1  A: 

You don't. The c++ standard has no concept of directories. It is up to the implementation to turn a string into a file handle. The contents of that string and what it maps to is OS dependent. Keep in mind that C++ can be used to write that OS, so it gets used at a level where asking how to iterate through a directory is not yet defined (because you are writing the directory management code).

Look at your OS API documentation for how to do this. If you need to be portable, you will have to have a bunch of ifdefs for various OS.

Matthew Scouten
+2  A: 

In addition to the above mentioned boost::filesystem you may want to examine wxWidgets::wxDir and Qt::QDir.

Both wxWidgets and Qt are open source, cross platform C++ frameworks.

wxDir provides a flexible way to traverse files recursively using Traverse() or a simpler GetAllFiles() function. As well you can implement the traversal with GetFirst() and GetNext() functions (I assume that Traverse() and GetAllFiles() are wrappers that eventually use GetFirst() and GetNext() functions).

QDir provides access to directory structures and their contents. There are several ways to traverse directories with QDir. You can iterate over the directory contents (including sub-directories) with QDirIterator that was instantiated with QDirIterator::Subdirectories flag. Another way is to use QDir's GetEntryList() function and implement a recursive traversal.

error.exit
Doxygen uses QT as its OS compatibility layer. The core tools doesn't use a GUI at all just the directory stuff (and others compenents).
caspin