arjacsoh
arjacsoh

Reputation: 9242

Find directories and sub-directories through recursion in C++

I want to create a method that reads a directory and finds and saves in a data structure all the directories included, as well as all the sub-directories of each directory. Specifically I want the names to be cited as:

folder1 folder11 folder12 folder2 folder21 folder22 folder23

I need obviously a function with recursion. I use temporary a class member method in a console application as:

private:
 struct dirent *ep;


void DirectoryReader::parseDirectory(char* readingDirectory)
{
char* tempDirectory = (char*)malloc(sizeof(readingDirectory) + 200); 
string temp = readingDirectory;

DIR *dp;
dp = opendir (readingDirectory);
   if (dp != NULL)
     {
       while (ep = readdir (dp))
       {
         puts (ep->d_name);

         temp += readingDirectory;
         temp += "/";
         temp += ep->d_name;

         char * buffer = new char[temp.length()];
         strcpy(buffer,temp.c_str());
         parseDirectory(buffer);
       }
         (void) closedir (dp);
     }
   else
     perror ("Couldn't open the directory");

}

Ok, I know not the best written code, but I want initially to have a view of the names caught. However it does not work properly, since it considers the name of the parent directory more than once. Even if I put the invocation of the same method out (not performing recursion) the first two names are . and .. . Why?

Could you suggest me a function doing the described process or indicate the correction demanded on this function?

Upvotes: 0

Views: 1595

Answers (2)

CapelliC
CapelliC

Reputation: 60034

as some comment pointed out, boost::filesystem is the usually way to go. But from your code it seems you are still a newbie to C++, so I've rewritten in C++ idiomatic way, adding a bit of useful display. HTH

#include <dirent.h>
#include <iostream>
#include <string>
using namespace std;

struct DirectoryReader
{
    static void parseDirectory(string readingDirectory, int level);
};

void DirectoryReader::parseDirectory(string readingDirectory, int level)
{
    if (DIR *dp = opendir(readingDirectory.c_str()))
    {
        cout << string(level, ' ') << readingDirectory << endl;
        while (struct dirent *ep = readdir(dp))
            if (ep->d_type == DT_DIR && ep->d_name[0] != '.')
                parseDirectory(readingDirectory + "/" + ep->d_name, level + 1);
        closedir(dp);
    }
    else
        cerr << "Couldn't open the directory " << readingDirectory << endl;
}

int main_parsedir(int argc, char **argv)
{
    if (argc > 1)
        DirectoryReader::parseDirectory(argv[1], 0);
    return 0;
}

note that in your code, storing struct dirent *ep; in class is plain wrong, because you overwrite it while recursing...

Upvotes: 4

PermanentGuest
PermanentGuest

Reputation: 5331

Directory enumeration functions usually return the current directory (.) and parent directory (..) links. You need to ignore them. Additionally you need to check for ep->d_type. I have written the following function for you. Please check if this works as expected. I didn't use the space separator for the output since the individual folders can have space character in them. Also, I'm not sure how you are going to use this output since it looses the tree structure.

#include "dirent.h"

const string theDelimiter = "\\";

class DirectoryReader
{
public:
    string DirectoryReader::parseDirectory(string readingDirectory, const string& aCurrentFolderName)
    {
        string aChildren;
        aChildren += theDelimiter;
        aChildren += aCurrentFolderName;

        DIR *dp = opendir (readingDirectory.c_str());
        if (dp != NULL)
        {
            struct dirent *ep = NULL;
            while ((ep = readdir (dp)) && ep->d_type == DT_DIR )
            {
                string aDirName = ep->d_name;

                //  Ignore current directory and the parent directory links
                if(!aDirName.compare(".") || !aDirName.compare(".."))
                    continue;

                //  Form the full directory path
                string aFullFolderName = readingDirectory;
                aFullFolderName += string("\\");
                aFullFolderName += aDirName;

                string aChildrenFolders = parseDirectory(aFullFolderName, aDirName);
                if(aChildrenFolders.compare(""))
                {
                    aChildren += aChildrenFolders;
                }
            }

            (void) closedir (dp);
        }
        else
            perror ("Couldn't open the directory");

        return aChildren;
    }
};

Upvotes: 2

Related Questions