温馨提示×

debian readdir如何工作

小樊
49
2026-09-04 11:49:36
栏目: 智能运维

在 Debian(以及其它 Linux 发行版)里,readdir 并不是“一个程序”,而是 C 库(glibc)提供的目录读取函数,底层依赖 Linux 内核的 getdents / getdents64 系统调用。下面从「用户态 → glibc → 内核 → 文件系统」逐层说明它是如何工作的。


一、readdir 是什么

readdir 定义在:

#include <dirent.h>

struct dirent *readdir(DIR *dirp);

作用:从已打开的目录流中读取下一个目录项(文件/子目录)

常见相关函数:

  • opendir() → 打开目录,返回 DIR*
  • readdir() → 逐个读取目录项
  • closedir() → 关闭目录
  • rewinddir() / seekdir() → 目录流定位

二、用户态调用流程(Debian / glibc)

1. opendir()

DIR *dir = opendir("/tmp");

内部大致做了:

  1. 调用 open("/tmp", O_RDONLY | O_DIRECTORY)
  2. 分配 DIR 结构体
  3. 初始化缓冲区(用于缓存目录项)

2. readdir()

struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
    printf("%s\n", entry->d_name);
}

readdir 的工作方式:

  • 不是每次系统调用都进内核
  • glibc 会:
    1. 如果内部缓冲区还有数据 → 直接返回
    2. 如果缓冲区空了 → 调用 getdents64() 一次读一批目录项
    3. 解析并返回其中一个 struct dirent

三、内核层:getdents64

readdir 最终调用:

int getdents64(int fd, struct linux_dirent64 *buf, int count);

这是在 VFS 层 实现的:

用户程序
  ↓
glibc readdir
  ↓
sys_getdents64
  ↓
vfs_readdir
  ↓
具体文件系统 (ext4 / xfs / overlayfs ...)

内核一次可能返回 多个目录项,减少系统调用次数。


四、文件系统层(以 ext4 为例)

在 ext4 中:

  • 目录本质是一个 文件
  • 目录内容由 目录项 (directory entry) 组成
  • ext4 使用:
    • 线性目录(旧)
    • HTree(哈希树)目录(默认)

读取过程:

  1. 内核从目录 inode 找到数据块
  2. 按块读取目录项
  3. 转换为 linux_dirent64
  4. 拷贝回用户空间缓冲区

五、struct dirent 内容说明

struct dirent {
    ino_t          d_ino;     // inode 号
    off_t          d_off;     // 偏移(用于 seekdir)
    unsigned short d_reclen;  // 记录长度
    unsigned char  d_type;    // 文件类型
    char           d_name[];  // 文件名
};

⚠️ 注意:

  • readdir 不保证顺序
  • ... 也可能被返回
  • 不是线程安全的(可用 readdir_r,但已废弃)

六、一个重要特性:迭代过程中文件变化

在 Debian / Linux 中:

  • 目录读取是 迭代器式
  • 如果在 readdir 过程中:
    • 新增文件 → 可能看到,也可能看不到
    • 删除文件 → 可能已跳过或已返回
  • 不保证一致性(除非使用 O_DIRECTORY + fs 特性 或快照)

七、简单示例

#include <dirent.h>
#include <stdio.h>

int main() {
    DIR *d = opendir(".");
    struct dirent *e;
    while ((e = readdir(d)))
        printf("%s\n", e->d_name);
    closedir(d);
}

八、相关命令/调试方式

  • strace ./a.out
    可以看到 openat, getdents64
  • ls -U
    不使用排序,接近 readdir 顺序
  • cat /proc/sys/fs/dentry-state

如果你愿意,我可以进一步讲:

  • readdir vs getdents 性能差异
  • 为什么 readdir 在 NFS 上行为不同
  • 如何用 getdents64 自己实现 readdir
  • Debian 上 ext4 / overlayfs 的具体差异

你想深入哪一块?

0