Traversing folders in C recursively


In this article, we have explored how to traverse folders in C recursively. We have used the dirent.h library to achieve this along with basic methods like readdir, opendir and closedir. Before going into the exact details, we will go through the basic ideas.

The C by default doesn't provide any of the methods with the I/O (Input and Output operations) functionalities.

In simple, terms it means without including any of the header files in C we can perform various functions and programs in C (given that complex mathematical functions are not used).

So, we can perform various actions without including header files but its rarely we don't perform any I/O (Input and Output operations). So, to perform various I/O (Input and Output operations) we use headers.

And after including these headers, the C interacts with I/O (Input and Output operations) with the help of streams.

Streams And Files
So, before actually starting the actual traversing, it's better to have an idea of how the files and I/O (Input and Output operations) are handled in C.

Let's start by exploring the terms Streams and Files. Initially, as we don't know whether the results are displayed to screen / any other I/O devices, apart from it is also not known that whether the input is going to come from a file or I/O. The streams can be used to point the files / I/O devices

So, C provides a beautiful technique of stream. These terms will help to communicate with the actual devices/sources.
And the actual devices are called as the files.

The stream can be divided into 2 types:-
1. Text Streams
2. Binary Streams

Text Streams
Here in the text streams, the character translations occur. It means that if we a \n in the file that is not displayed as \n rather it is displayed as a line change. This means during the reading the actual is somewhat changed and modified data is displayed.

Binary Streams
But here in the Binary Stream the character translations don't occur. It means that if we a \n in the file that is displayed as \n rather than displaying it as a line change. This means during the reading the actual is not modified at all data is displayed.

Now let's see how files are handled.

Again it should be noted that C doesn't provide any direct method for file handling and traversals.

So, the header we are going to use is:

<dirent.h>

Now let's have a basic idea about the library we are using.

  1. This header defines the data type DIR using the typedef . This DIR represents a directory of a stream. The stream that has been explained above.
  2. It also defines a structure, the members of the structure are a character array (to store file name) and an additional field to store the file serial number(ino_t).

**Common Functions used in File Traversals :-

  1. readdir()
  2. opendir()
  3. closedir()**

1. readdir()

It is defined in the library <dirent.h>.

The prototype of the funtion :-

struct dirent *readdir(DIR *dirp);

What is DIR datatype?
As , mentioned that C interacts everyhting with the help of streams and DIR is one of the ways of stream interaction. This datatype should alwys be used with pointer because interacting with direct instance of DIR can result in errors later.

The argument is of the type DIR pointer representing the current position in the directory stream and when this call is invoked this function returns the position of the pointer that would be pointing to the next directory in the stream interaction.

It returns the null pointer when we reach towards the end of the file directory.

Sample code will make the function use clear:-

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

int main()
{
    DIR *dir;
    struct dirent *dp;
    char * file_name;
    dir = opendir("/Users/babayaga/Desktop/foldertest");
    while ((dp=readdir(dir)) != NULL) {
        
       file_name = dp->d_name; 
        printf("The File Name :-  \"%s\"\n",file_name);
    }
    closedir(dir);
    return 0;
}

2. opendir()

It is defined in the library <dirent.h>.

The prototype of the funtion :-

DIR *opendir(const char *fold_name);

The argument passed is the directory name and it is made const so that the function doesn't modify the directory due to some errors.

On success, it returns a pointer of DIR type else it returns null.

3. closedir()

Similar to the case of streams, the opened streams are needed to close.

It is defined in the library <dirent.h>.

The prototype of the funtion :-

int closedir(DIR *dirp);

This function helps in closing the opened directory. If closing successful then it returns 0 else is some error occurs then **-1 ** is returned.

Now after learning the required pre-requisites, let's start implementing codes.

Sample Code 1:
In this code, we will simply print the contents of the directory path we are passing as an argument . This code doesn't further explore the sub-directories.

#include <stdio.h> 
#include <dirent.h> 
  
int main(void) 
{ 
    struct dirent *de;  // Pointer for directory entry 
  
    // opendir() returns a pointer of DIR type.  
    char ch[1000000];
    scanf("%s",ch);// this is added to take input the path of directory to be searched
    DIR *dr = opendir(ch); 
  
    if (dr == NULL)  // opendir returns NULL if couldn't open directory 
    { 
        printf("Could not open current directory" ); 
        return 0; 
    } 

    while ((de = readdir(dr)) != NULL) 
            printf("%s\n", de->d_name); 
  
    closedir(dr);     
    return 0; 
} 

Method to run the program:-

cc mytest.c //file name
./a.out //executable code
/Users/babayaga/Desktop/foldertest //this is the path of the directory
//(imp point to note here is that check the // direction of slash depending on the Operating System you are using)

code1
Sample Code 2:

In this code, we will recursively print the contents of each directory and further if a directory is encountered that directory is also explored.

In simple, words it will list all the files starting from the given location.

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

void myfilerecursive(char *path);


int main()
{
   
    char name[100000]; 
    printf("Enter path to list files: ");
    scanf("%s", name);

    myfilerecursive(name);

    return 0;
}

void myfilerecursive(char *basePath)
{
    char path[1000];
    struct dirent *dp;
    DIR *dir = opendir(basePath);

   
    if (!dir)
        return;

    while ((dp = readdir(dir)) != NULL)
    {
        if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0)
        {
            printf("%s\n", dp->d_name);
            strcpy(path, basePath);
            strcat(path, "/");
            strcat(path, dp->d_name);

            myfilerecursive(path);
        }
    }

    closedir(dir);
}

Method to run the program:-

cc mytest2.c //file name
./a.out //executable code
/Users/babayaga/Desktop/foldertest //this is the path of the directory
//(imp point to note here is that check the // direction of slash depending on the Operating System you are using)

Screenshot-2020-03-17-at-1.40.24-PM
So, this code is different from the sample code 1 in the sense that the sample code 1 will not go inside the directory if it encounters any directory during the listing of the directories of the given path.

The abstarct structure of the folder in which we are testing the code is below given :- Screenshot-2020-03-17-at-1.51.23-PM

With this article at OpenGenus, you must have a complete idea of traversing folders in C recursively.