在 Debian(以及其它 Linux 发行版、POSIX 系统)里,opendir 和 readdir 是配合使用的一组目录操作函数,都属于 <dirent.h> 提供的目录遍历 API。
下面从“关系、用法、原理、注意点”几个方面说明。
opendir 和 readdir 的关系可以简单理解为:
opendir打开目录,返回一个“目录流”
readdir从“目录流”中逐个读取目录项
opendir(path)
↓
DIR * (目录流)
↓
readdir(dirp) → struct dirent *
↓
readdir(dirp) → struct dirent *
↓
...
closedir(dirp)
opendir#include <dirent.h>
DIR *opendir(const char *name);
name 是目录路径DIR *(目录流)NULL,并设置 errnoreaddir#include <dirent.h>
struct dirent *readdir(DIR *dirp);
dirp 是 opendir 返回的目录流struct dirent *NULLNULL,并设置 errno⚠️ 返回 NULL 不一定代表出错,需要配合 errno 判断。
#include <stdio.h>
#include <dirent.h>
int main(int argc, char *argv[]) {
DIR *dir;
struct dirent *entry;
dir = opendir(".");
if (dir == NULL) {
perror("opendir");
return 1;
}
while ((entry = readdir(dir)) != NULL) {
printf("%s\n", entry->d_name);
}
closedir(dir);
return 0;
}
readdir 返回的是:
struct dirent {
ino_t d_ino; // inode 号
off_t d_off; // 偏移量
unsigned short d_reclen; // 记录长度
unsigned char d_type; // 文件类型
char d_name[]; // 文件名
};
常见 d_type:
DT_REG:普通文件DT_DIR:目录DT_LNK:符号链接在 Debian(glibc + Linux)中:
opendir → 内部调用 open() + fdopendir()readdir → 内部可能使用 getdents64 系统调用也就是说:
readdir并不是每次都进内核,而是从opendir建立的缓冲区中读取
readdir 不是线程安全的int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
(不过现代 glibc 中 readdir_r 已不推荐)
opendir错误示例:
while (readdir(opendir("."))) { }
✅ 正确做法:先 opendir,再循环 readdir
closedir否则会造成文件描述符泄漏。
在 Debian 中,
opendir用于打开目录并创建目录流,readdir用于从该目录流中逐项读取文件信息,二者是“打开—读取”的配套关系。
如果你愿意,我也可以:
scandiropendir / readdir 与 stat 的配合你可以直接说你的使用场景。