Listing directory contents is a fundamental operation in C programming. It is useful for file management, system utilities, and automation tasks. Directories may contain files, subdirectories, and hidden entries, so handling them correctly is essential for building robust programs.
In this tutorial, we will cover multiple approaches to list directories in C. You will learn to handle empty and non-empty directories, skip special entries, perform recursive traversal, and display file attributes such as size. By the end, you will have a solid understanding of directory management in C.
Understanding the Problem
A directory may include files, subdirectories, hidden files, or special entries like "."
and ".."
that represent the current and parent directories. Attempting to read directories without considering these entries can lead to infinite loops or incorrect listings.
C provides functions like opendir()
, readdir()
, and closedir()
for reading directories on UNIX-like systems. On Windows, a compatible dirent.h
or platform-specific APIs are used. Error handling and cross-platform compatibility are crucial to make the program reliable.
Program 1: Listing Directory Contents
The simplest approach is to list all entries, including files and subdirectories:
#include <stdio.h>
#include <dirent.h>
int main() {
const char *dirname = "."; // cwd
DIR *dir = opendir(dirname);
if (dir == NULL) {
printf("Error: Could not open directory '%s'.\n", dirname);
return 1;
}
struct dirent *entry;
printf("Contents of directory '%s':\n", dirname);
while ((entry = readdir(dir)) != NULL) {
printf("%s\n", entry->d_name);
}
closedir(dir);
return 0;
}
Here, opendir()
opens the directory, readdir()
retrieves entries, and closedir()
closes it. This program prints everything, including "."
and ".."
.
Program 2: Filtering Out "."
and ".."
For a cleaner output, you can skip the special entries:
#include <stdio.h>
#include <dirent.h>
#include <string.h>
int main() {
const char *dirname = "."; // cwd
DIR *dir = opendir(dirname);
if (dir == NULL) {
printf("Error: Could not open directory '%s'.\n", dirname);
return 1;
}
struct dirent *entry;
printf("Contents of directory '%s' (excluding '.' and '..'):\n", dirname);
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
printf("%s\n", entry->d_name);
}
}
closedir(dir);
return 0;
}
By checking each entry with strcmp()
, we exclude "."
and ".."
, focusing only on actual files and subdirectories.
Program 3: Recursive Listing of Directory Contents
To list all files in nested subdirectories, recursion is required:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <dirent.h>
#ifdef _WIN32
#include <io.h>
#endif
void list_directory_recursive(const char *path, int level) {
struct dirent *entry;
DIR *dp = opendir(path);
if (dp == NULL) {
printf("Error: Could not open directory '%s'.\n", path);
return;
}
while ((entry = readdir(dp)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
for (int i = 0; i < level; i++) printf(" "); // Indentation
printf("%s\n", entry->d_name);
char full_path[1024];
snprintf(full_path, sizeof(full_path), "%s/%s", path, entry->d_name);
struct stat st;
if (stat(full_path, &st) == 0 && S_ISDIR(st.st_mode)) {
list_directory_recursive(full_path, level + 1);
}
}
closedir(dp);
}
int main() {
const char *dirname = "."; // cwd
printf("Recursive contents of directory '%s':\n", dirname);
list_directory_recursive(dirname, 0);
return 0;
}
This program recursively traverses subdirectories, printing entries with indentation to visualize the structure.
Program 4: Recursive Listing with File Sizes and Attributes
For more detailed information, including file size and type:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <dirent.h>
#ifdef _WIN32
#include <io.h>
#endif
void list_directory_detailed(const char *path, int level) {
struct dirent *entry;
DIR *dp = opendir(path);
if (dp == NULL) {
printf("Error: Could not open directory '%s'.\n", path);
return;
}
while ((entry = readdir(dp)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
char full_path[1024];
snprintf(full_path, sizeof(full_path), "%s/%s", path, entry->d_name);
struct stat st;
if (stat(full_path, &st) == 0) {
for (int i = 0; i < level; i++) printf(" ");
if (S_ISDIR(st.st_mode)) {
printf("[DIR] %s\n", entry->d_name);
list_directory_detailed(full_path, level + 1);
} else {
printf("[FILE] %s (%lld bytes)\n", entry->d_name, (long long)st.st_size);
}
} else {
printf("Error retrieving info for '%s'\n", full_path);
}
}
closedir(dp);
}
int main() {
const char *dirname = "."; // cwd
printf("Detailed recursive listing of '%s':\n", dirname);
list_directory_detailed(dirname, 0);
return 0;
}
Using stat()
, this program retrieves file size and type. Directories are processed recursively, and indentation improves readability.
FAQs
Q1: Can this program display file permissions and modification times?
Yes, you can extract permissions and times from the stat
structure. Functions like localtime()
and strftime()
can format timestamps for display.
Q2: Is recursive listing safe for very deep directory trees?
Recursion works well, but extremely deep trees may risk stack overflow. Iterative solutions or limiting recursion depth can prevent this.
Q3: How can I filter hidden files?
You can skip entries starting with .
to hide hidden files.
Q4: Can this program be used on both Linux and Windows?
Yes, with a compatible dirent.h
on Windows or by using platform-specific APIs. Conditional compilation ensures portability.
Q5: Can I sort the files alphabetically?
Yes, store entries in an array, sort them, and then print. readdir()
itself returns entries in filesystem order, not alphabetically.
Conclusion
Listing directories in C can be done in several ways, from basic listings to recursive traversal with detailed attributes. Proper handling of "."
and ".."
, checking for errors, and cross-platform considerations ensure your program is reliable.
By mastering these techniques, you can build file explorers, automated file management tools, and other applications that interact with the filesystem effectively.
References & Additional Resources
A curated collection of textbooks, documentation, and tutorials for working with directories, file I/O, and system calls in C.
- Kernighan, B.W., & Ritchie, D.M. (1988). The C Programming Language (2nd Edition). Prentice Hall – The foundational text covering file handling, standard libraries, and system-level programming in C.
- GeeksforGeeks: List Files in a Directory in C – An example of listing files using
dirent.h
. - Linux man page: opendir – Official Linux manual page for
opendir()
, explaining how to open directories in C. - dirent.h for Windows – A port of the POSIX
dirent.h
API for Windows systems. - Tutorialspoint: C Programming File I/O – Beginner-friendly introduction to file input/output operations in C.
- Stat Structure Documentation – Official documentation for the
stat
system call used to retrieve file and directory metadata. - Stack Overflow: Cross-Platform Directory Listing in C – Community discussion on portable approaches for directory listing across operating systems.