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.hfor directory operations andsys/stat.hfor 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_DIRto 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 direntpointer. -
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_typefor simpler checks (DT_DIRfor 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_MAXif 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
$197

$78
$78