C program to list all files in a directory recursively

Write a C program to list all files in a directory. How to list all files in a directory recursively. How to use readdir() function to list all files in a directory recursively. Logic to list all files and sub-directories of a directory in C programming. How to use opendir(), readdir() and closedir() library functions.

Required knowledge

Basic Input Output, File handling, Recursion

In programming while file manipulation, several times we come across a problem to list files in a directory. List files in a directory and recursively in its sub-directories. However, many C programmers don't know how to get list of all files and directories within a directory. In this post I will explain how to list files and directories in a directory.

How to print files and directories in tree structure in C programming

The readdir() function

struct dirent *readdir(DIR *dirp);

function is defined in dirent.h header file. It returns pointer to a structure dirent type representing directory entry at the current position in directory stream dirp. On every call to readdir() method, it returns file/directory at current position in directory stream. readdir() returns NULL pointer if reached at the end of directory stream.

But wait, readdir(DIR *dirp) function accepts a parameter of DIR type. How to get reference to DIR type.

The opendir() function

DIR *opendir(const char *dirname);

is also defined in dirent.h header file. Similar to file streams, opendir() opens a directory stream corresponding to the file path pointed by dirname. By default the opened directory stream points to first entry in the directory.

On success, the function returns a pointer to structure of DIR type. Otherwise NULL pointer. The returned value can be further used to perform operations on directory.

Similar to file stream, we open a directory stream, perform some action and finally close the stream. To close a directory stream we use closedir() function.

The closedir() function

int closedir(DIR *dirp);

is also present under same library file. It closes a directory pointed by dirp pointer.

On success the function returns 0, otherwise -1.

How to list all files and directories of a directory

Step by step descriptive logic to list all files and directories in a directory.

  1. Input source path to list all files and sub-directories. Store it in some variable say path.
  2. Open directory stream using opendir() and store its reference to *dir of DIR type.
  3. Initialize another variable of pointer to structure dirent type, say struct dirent *dp.
  4. Read next element from directory stream using dp = readdir(dir).
  5. Print current directory stream item name, using dp->name.
  6. Repeat step 4-5 till dp != NULL.
  7. Finally, close the directory stream pointed by dir variable.

Program to list all files and sub-directories in a directory

/**
 * C program to list all files and sub-directories in a directory.
 */

#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>


void listFiles(const char *path);

int main()
{
    // Directory path to list files
    char path[100];

    // Input path from user
    printf("Enter path to list files: ");
    scanf("%s", path);

    listFiles(path);

    return 0;
}


/**
 * Lists all files and sub-directories at given path.
 */
void listFiles(const char *path)
{
    struct dirent *dp;
    DIR *dir = opendir(path);

    // Unable to open directory stream
    if (!dir) 
        return; 

    while ((dp = readdir(dir)) != NULL)
    {
        printf("%s\n", dp->d_name);
    }

    // Close directory stream
    closedir(dir);
}

You can easily convert above function to work for recursive directory listing. Check below program if facing difficulties implementing it recursive way.

Program to list all files and sub-directories of a directory recursively

/**
 * C program to list contents of a directory recursively.
 */

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

void listFilesRecursively(char *path);


int main()
{
    // Directory path to list files
    char path[100];

    // Input path from user
    printf("Enter path to list files: ");
    scanf("%s", path);

    listFilesRecursively(path);

    return 0;
}


/**
 * Lists all files and sub-directories recursively 
 * considering path as base path.
 */
void listFilesRecursively(char *basePath)
{
    char path[1000];
    struct dirent *dp;
    DIR *dir = opendir(basePath);

    // Unable to open directory stream
    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);

            // Construct new path from our base path
            strcpy(path, basePath);
            strcat(path, "/");
            strcat(path, dp->d_name);

            listFilesRecursively(path);
        }
    }

    closedir(dir);
}}

Output

Enter path to list files: .
.git
COMMIT_EDITMSG
config
description
FETCH_HEAD
HEAD
hooks
pack
ORIG_HEAD
packed-refs
refs
heads
master
remotes
origin
HEAD
master
tags
.gitignore
.vscode
c_cpp_properties.json
bin
a.exe
c-program-to-find-maximum-and-minimum-range-of-data-types-using-macro.c
c-programming-ws.code-workspace
data
append.txt
blanks.txt
compare1.txt
compare2.txt
copy-file.txt
empty-lines.txt
even-numbers.txt
file1.txt
file2.txt
file3.txt
file4.txt
merged-file.txt
numbers.txt
odd-numbers.txt
prime-numbers.txt
LICENSE
README.md
src
file
append-data.c
check-file-properties.c
compare-file.c
copy-file-contents.c
copy-file-using-function.c
count-characters-words-lines-in-file.c
count-occurrences-of-all-words-in-file.c
create-and-write-contents-to-file.c
delete-all-blank-lines.c
delete-specific-line.c
delete-word-from-file.c
directory-exists.c
file-exists.c
file-programming-example-list.md
find-word-in-file.c
list-files.c
merge-file.c
print-source-of-current-file.c
read-from-file-using-fgetc.c
read-from-file-using-fgets.c
read-numbers-write-even-odd-prime-to-separate-file.c
remove-empty-lines.c
rename-file.c
replace-line-in-file.c
replace-word-in-file.c
replace-word.c
toggle-case-of-file-contents.c
stdlib
atof.c
atoi.c
atol.c
atoll.c
strtol.c
strtoll.c
strtoul.c
strtoull.c

Let's raise the level. The above recursive method prints all files and sub-directories in same indentation. Its very difficult to know which files are in which directory. So lets print all files and sub-directories in tree structure.

Program to print all files and sub-directories in tree structure

/**
 * C program to list file and sub-directories of a directory 
 * recursively in tree structure.
 */

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>


void tree(char *basePath, const int root);

int main()
{
    // Directory path to list files
    char path[100];

    // Input path from user
    printf("Enter path to list files: ");
    scanf("%s", path);

    tree(path, 0);

    return 0;
}


/**
 * Tree, prints all files and sub-directories of a given 
 * directory in tree structure.
 * 
 * @param basePath Base path to traverse directory
 * @param root     Integer representing indention for current directory
 */
void tree(char *basePath, const int root)
{
    int i;
    char path[1000];
    struct dirent *dp;
    DIR *dir = opendir(basePath);

    // Unable to open directory stream
    if (!dir)
        return;

    while ((dp = readdir(dir)) != NULL)
    {
        if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0)
        {
            for (i=0; id_name);

            // Construct new path from the current base path
            strcpy(path, basePath);
            strcat(path, "/");
            strcat(path, dp->d_name);

            // Recursively print all files and sub-directories
            tree(path, root + 2);
        }
    }

    closedir(dir);
}

Output

Enter path to list files: .
├─.git
│ ├─COMMIT_EDITMSG
│ ├─config
│ ├─description
│ ├─FETCH_HEAD
│ ├─HEAD
│ ├─ORIG_HEAD
│ ├─packed-refs
│ ├─refs
│ │ ├─heads
│ │ │ ├─master
│ │ ├─remotes
│ │ │ ├─origin
│ │ │ │ ├─HEAD
│ │ │ │ ├─master
│ │ ├─tags
├─.gitignore
├─.vscode
│ ├─c_cpp_properties.json
├─bin
│ ├─a.exe
├─c-program-to-find-maximum-and-minimum-range-of-data-types-using-macro.c
├─c-programming-ws.code-workspace
├─data
│ ├─append.txt
│ ├─blanks.txt
│ ├─compare1.txt
│ ├─compare2.txt
│ ├─copy-file.txt
│ ├─empty-lines.txt
│ ├─even-numbers.txt
│ ├─file1.txt
│ ├─file2.txt
│ ├─file3.txt
│ ├─file4.txt
│ ├─merged-file.txt
│ ├─numbers.txt
│ ├─odd-numbers.txt
│ ├─prime-numbers.txt
├─LICENSE
├─README.md
├─src
│ ├─file
│ │ ├─append-data.c
│ │ ├─check-file-properties.c
│ │ ├─compare-file.c
│ │ ├─copy-file-contents.c
│ │ ├─copy-file-using-function.c
│ │ ├─count-characters-words-lines-in-file.c
│ │ ├─count-occurrences-of-all-words-in-file.c
│ │ ├─create-and-write-contents-to-file.c
│ │ ├─delete-all-blank-lines.c
│ │ ├─delete-specific-line.c
│ │ ├─delete-word-from-file.c
│ │ ├─directory-exists.c
│ │ ├─file-exists.c
│ │ ├─file-programming-example-list.md
│ │ ├─find-word-in-file.c
│ │ ├─list-files.c
│ │ ├─merge-file.c
│ │ ├─print-source-of-current-file.c
│ │ ├─read-from-file-using-fgetc.c
│ │ ├─read-from-file-using-fgets.c
│ │ ├─read-numbers-write-even-odd-prime-to-separate-file.c
│ │ ├─remove-empty-lines.c
│ │ ├─rename-file.c
│ │ ├─replace-line-in-file.c
│ │ ├─replace-word-in-file.c
│ │ ├─replace-word.c
│ │ ├─toggle-case-of-file-contents.c
│ ├─stdlib
│ │ ├─atof.c
│ │ ├─atoi.c
│ │ ├─atol.c
│ │ ├─atoll.c
│ │ ├─strtol.c
│ │ ├─strtoll.c
│ │ ├─strtoul.c
│ │ ├─strtoull.c

Happy coding 😉

About Pankaj

Pankaj Prakash is the founder, editor and blogger at Codeforwin. He loves to learn new techs and write programming articles especially for beginners. He works at Vasudhaika Software Sols as a Software Design Engineer and manages Codeforwin. In short Pankaj is Web developer, Blogger, Learner, Tech and Music lover.

Comments and discussion
Have a doubt, write here. I will help my best.
Before commenting you must escape your source code before commenting. Paste your source code inside
<pre><code> ----Your Source Code---- </code></pre>