How to recursively list directories in C on Linux?
How to Recursively List Directories in C on Linux
To recursively list directories in C on Linux, you can use the POSIX API, specifically the functions provided by the dirent.h
library for directory traversal. The approach involves reading a directory, identifying subdirectories, and recursively processing each subdirectory.
Here’s a complete guide:
Steps
- Include Required Libraries: Use
dirent.h
for directory operations andsys/stat.h
for file type checks. - Open the Directory: Use
opendir()
to open a directory. - Read Entries: Use
readdir()
to iterate over directory entries. - Check Entry Types: Use
stat()
orDT_DIR
to identify subdirectories. - Recursive Call: For each subdirectory (excluding
.
and..
), call the function recursively. - Handle Edge Cases: Exclude hidden directories or handle symbolic links if necessary.
Code Implementation
#include <stdio.h> #include <stdlib.h> #include <dirent.h> #include <sys/stat.h> #include <string.h> // Function to recursively list directories void listDirectories(const char *basePath) { struct dirent *entry; DIR *dir = opendir(basePath); if (dir == NULL) { perror("Unable to open directory"); return; } while ((entry = readdir(dir)) != NULL) { // Skip "." and ".." if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { continue; } // Construct full path char path[1024]; snprintf(path, sizeof(path), "%s/%s", basePath, entry->d_name); // Check if the entry is a directory struct stat statbuf; if (stat(path, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) { printf("Directory: %s\n", path); // Recursive call listDirectories(path); } } closedir(dir); } int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "Usage: %s <directory_path>\n", argv[0]); exit(EXIT_FAILURE); } listDirectories(argv[1]); return 0; }
Explanation
-
Opening the Directory: The function
opendir(basePath)
opens the specified directory for reading. If the directory cannot be opened,opendir()
returnsNULL
, and we handle the error usingperror
. -
Reading Entries: The
readdir()
function reads each entry in the directory, returning astruct dirent
pointer. -
Checking File Type:
stat()
: Fetches metadata about the file. TheS_ISDIR()
macro checks if the file is a directory.- Alternatively, you can use
entry->d_type
for simpler checks (DT_DIR
for directories). However, this field may not always be reliable on certain filesystems.
-
Skipping
.
and..
: These special entries represent the current directory and parent directory, so they must be ignored to avoid infinite recursion. -
Recursive Call: For each subdirectory found,
listDirectories(path)
is called recursively. -
Closing the Directory: After processing all entries, the directory is closed using
closedir()
.
Output Example
For a directory structure like this:
/home/user/test
├── dir1
│ └── dir2
│ └── file.txt
└── dir3
Running ./listDirectories /home/user/test
produces:
Directory: /home/user/test/dir1
Directory: /home/user/test/dir1/dir2
Directory: /home/user/test/dir3
Considerations
- Path Length: Ensure the buffer (
path[1024]
) is large enough for the full path. UsePATH_MAX
if available. - Symbolic Links: Use
lstat()
instead ofstat()
if you want to handle symbolic links separately. - Error Handling: Add checks for permission errors or inaccessible directories.
- Hidden Files/Directories: To include hidden directories (starting with
.
), ensure no additional filtering is applied.
Enhanced Version with File Listing
If you also want to list files within directories, include them in the output:
void listContents(const char *basePath) { struct dirent *entry; DIR *dir = opendir(basePath); if (dir == NULL) { perror("Unable to open directory"); return; } while ((entry = readdir(dir)) != NULL) { if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { continue; } char path[1024]; snprintf(path, sizeof(path), "%s/%s", basePath, entry->d_name); struct stat statbuf; if (stat(path, &statbuf) == 0) { if (S_ISDIR(statbuf.st_mode)) { printf("Directory: %s\n", path); listContents(path); // Recursive call } else { printf("File: %s\n", path); } } } closedir(dir); }
Example Output
For the same directory structure:
Directory: /home/user/test/dir1
File: /home/user/test/dir1/file1.txt
Directory: /home/user/test/dir1/dir2
File: /home/user/test/dir1/dir2/file.txt
Directory: /home/user/test/dir3
This version differentiates files from directories while maintaining recursive traversal.
GET YOUR FREE
Coding Questions Catalog