25

I want to list folders in a directory in C++, ideally in a portable (working in the major Operating Systems) way. I tried using POSIX, and it works correctly, but how can i identify whether the found item is a folder?

m4tx
  • 4,139
  • 5
  • 37
  • 61

6 Answers6

28

You could use opendir() and readdir() to list directories and subdirectories. The following example prints all subdirectories inside the current path:

#include <dirent.h>
#include <stdio.h>

int main()
{
    const char* PATH = ".";

    DIR *dir = opendir(PATH);

    struct dirent *entry = readdir(dir);

    while (entry != NULL)
    {
        if (entry->d_type == DT_DIR)
            printf("%s\n", entry->d_name);

        entry = readdir(dir);
    }

    closedir(dir);

    return 0;
}
David
  • 2,663
  • 3
  • 24
  • 41
24

Using the C++17 std::filesystem library:

std::vector<std::string> get_directories(const std::string& s)
{
    std::vector<std::string> r;
    for(auto& p : std::filesystem::recursive_directory_iterator(s))
        if (p.is_directory())
            r.push_back(p.path().string());
    return r;
}
wally
  • 10,717
  • 5
  • 39
  • 72
  • I believe that since this is more portable way and still doesn't use any external libraries, it deserves more to be an accepted answer now. – m4tx Jan 29 '18 at 13:15
  • I get Segmentation faults once I cross the local application path. Eg. List the directories of /home/$USER. is this just me or this filesystem very unstable on my system? – Melroy van den Berg Jun 07 '19 at 00:31
  • 2
    I believe `p.status().type() == std::filesystem::file_type::directory` can be replaced with `p.is_directory()`, unless there are subtle differences I'm unaware of. – Tim M. Jul 08 '19 at 18:30
10

Here follows a (slightly modified) quote from the boost filesystem documentation to show you how it can be done:

void iterate_over_directories( const path & dir_path )         // in this directory,
{
  if ( exists( dir_path ) ) 
  {
    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()) )
      {
        //... here you have a directory
      }
    }
  }
}
Benoît
  • 16,798
  • 8
  • 46
  • 66
5

Look up the stat function. Here is a description. Some sample code:

struct stat st;
const char *dirname = "dir_name";
if( stat( dirname, &st ) == 0 && S_ISDIR( st.st_mode ) ) {
    // "dir_name" is a subdirectory of the current directory
} else {
    // "dir_name" doesn't exist or isn't a directory
}
Graeme Perrow
  • 56,086
  • 21
  • 82
  • 121
2

I feel compelled to mention PhysFS. I just integrated it into my own project. It provides true cross-platform (Mac / Linux / PC) file operations and can even unpack various archive definitions such as zip, 7zip, pak, and so on. It has a few functions (PHYSFS_isDirectory, PHYSFS_enumerateFiles) which can determine what you are asking for as well.

James
  • 5,355
  • 2
  • 18
  • 30
1

Under Windows, you can use _findfirst() and _findnext() to iterate through the contents of a directory, and then use CreateFile() and GetFileInformationByHandle() to determine whether a particular entry is a directory or a folder. (Yes, CreateFile(), with the appropriate arguments, to examine an existing file. Ain't life grand?)

For reference, some classes where I implemented code that uses those calls can be seen here and here

Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234