在 Ubuntu(Linux)下,opendir 和 readdir 是 POSIX 标准 API,通常配合在一起用来遍历目录。下面从用法、示例到注意事项给你一个完整说明。
opendir():打开目录,返回一个 DIR *readdir():读取目录项,每次返回一个 struct dirent *closedir():关闭目录流程一般是:
opendir -> readdir (循环) -> closedir
#include <dirent.h>
DIR *opendir(const char *name);
struct dirent *readdir(DIR *dirp);
int closedir(DIR *dirp);
struct dirent 关键字段:
struct dirent {
ino_t d_ino;
off_t d_off;
unsigned short d_rendtl;
unsigned char d_type; // 文件类型
char d_name[256]; // 文件名
};
#include <stdio.h>
#include <dirent.h>
int main(int argc, char *argv[]) {
const char *path = argc > 1 ? argv[1] : ".";
DIR *dir = opendir(path);
if (!dir) {
perror("opendir");
return 1;
}
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
printf("%s\n", entry->d_name);
}
closedir(dir);
return 0;
}
编译运行:
gcc listdir.c -o listdir
./listdir /tmp
. 和 ..while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 ||
strcmp(entry->d_name, "..") == 0)
continue;
printf("%s\n", entry->d_name);
}
d_type(不一定可靠)if (entry->d_type == DT_DIR) {
printf("[DIR] %s\n", entry->d_name);
}
⚠️ 某些文件系统(如某些网络文件系统)d_type 可能是 DT_UNKNOWN
stat(最可靠)#include <sys/stat.h>
struct stat st;
char fullpath[512];
snprintf(fullpath, sizeof(fullpath), "%s/%s", path, entry->d_name);
if (stat(fullpath, &st) == 0) {
if (S_ISDIR(st.st_mode))
printf("[DIR] %s\n", entry->d_name);
else
printf("[FILE] %s\n", entry->d_name);
}
void list_dir(const char *path) {
DIR *dir = opendir(path);
if (!dir) return;
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
if (!strcmp(entry->d_name, ".") ||
!strcmp(entry->d_name, ".."))
continue;
char fullpath[512];
snprintf(fullpath, sizeof(fullpath), "%s/%s", path, entry->d_name);
struct stat st;
if (stat(fullpath, &st) == 0 && S_ISDIR(st.st_mode)) {
printf("DIR: %s\n", fullpath);
list_dir(fullpath);
} else {
printf("FILE: %s\n", fullpath);
}
}
closedir(dir);
}
❌ 忘记 closedir → 文件描述符泄漏
❌ 用 readdir 返回指针后长期保存(struct dirent 会被覆盖)
❌ 用 readdir 做线程安全操作(它不是线程安全的)
✅ 多线程请用 readdir_r(已废弃但可用)或 readdir64_r
opendir 打开目录,readdir 一个个读,closedir 收尾,stat 判断类型
如果你有具体需求(比如:按后缀过滤、统计文件数、递归删除),可以直接说,我可以给你对应代码。