在 Debian(以及一般 Linux/glibc) 里,opendir / closedir / readdir 并不是系统调用,而是 glibc 的库函数,底层最终调用的是 open + getdents64 等系统调用。
下面从“如何使用”和“如何自己实现一个简化版 opendir”两个角度说明。
#include <dirent.h>
#include <stdio.h>
int main(void) {
DIR *dir = opendir(".");
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 test.c -o test
| 函数 | 说明 |
|---|---|
open() |
打开目录(O_RDONLY |
getdents64() |
读取目录项 |
close() |
关闭目录 |
⚠️ 目录不能用 read(),必须用 getdents64
struct __dirstream {
int fd; // 目录文件描述符
char *buf; // 缓冲区
size_t buf_size;
off_t offset;
struct dirent *ptr;
};
DIR * 实际上就是 struct __dirstream *
#ifndef MYDIR_H
#define MYDIR_H
#include <sys/types.h>
#include <dirent.h>
typedef struct {
int fd;
char buf[4096];
size_t pos;
size_t end;
struct dirent ent;
} MYDIR;
MYDIR *my_opendir(const char *path);
struct dirent *my_readdir(MYDIR *dir);
void my_closedir(MYDIR *dir);
#endif
#include "mydir.h"
#include <fcntl.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
MYDIR *my_opendir(const char *path) {
int fd = open(path, O_RDONLY | O_DIRECTORY);
if (fd < 0)
return NULL;
MYDIR *dir = calloc(1, sizeof(MYDIR));
dir->fd = fd;
return dir;
}
struct dirent *my_readdir(MYDIR *dir) {
if (dir->pos >= dir->end) {
dir->end = syscall(SYS_getdents64, dir->fd, dir->buf, sizeof(dir->buf));
dir->pos = 0;
if (dir->end <= 0)
return NULL;
}
struct dirent *d = (struct dirent *)(dir->buf + dir->pos);
dir->pos += d->d_reclen;
return d;
}
void my_closedir(MYDIR *dir) {
close(dir->fd);
free(dir);
}
MYDIR *dir = my_opendir(".");
struct dirent *e;
while ((e = my_readdir(dir)))
printf("%s\n", e->d_name);
my_closedir(dir);
dpkg -S opendir
源码位置(glibc):
sysdeps/unix/sysv/linux/opendir.c
sysdeps/unix/sysv/linux/getdents64.c
查看 man:
man 3 opendir
man 2 getdents64
opendir 是 glibc 封装open + getdents64如果你是:
opendirgetdents64如果你愿意,我可以: