温馨提示×

linux readdir为啥效率很低

小樊
44
2026-10-17 07:37:31
栏目: 智能运维

readdir 在 Linux 下“效率低”通常不是函数本身慢,而是使用方式 + 文件系统特性 + 历史实现共同造成的。下面分点说清楚原因,以及什么时候它会慢、怎么优化。


一、先澄清:readdir 本身不一定慢

  • readdir 只是从已经打开的目录句柄里取下一个条目
  • 真正的开销在:
    • opendir
    • 内核读取目录项(getdents)
    • 对每个文件再做 stat

二、常见导致 readdir 慢的真实原因

1️⃣ 每次 readdir 后都 stat(最常见)

很多人写的是:

while ((ent = readdir(dir))) {
    stat(ent->d_name, &st); // 慢!
}

问题:

  • readdir 不返回文件类型/元数据
  • 每个文件都要一次 stat 系统调用
  • 目录有 10 万个文件 = 10 万次 stat

✅ 解决:

  • 用 readdir + d_type(仅部分文件系统支持)
  • 或用 statx / getdents64

2️⃣ 目录里文件太多(百万级)

  • 传统 ext3/ext4 目录是线性结构
  • readdir 要顺序扫整个目录
  • 没有索引,不能跳

表现:

  • 第一次 readdir 慢
  • 缓存失效后更慢

✅ 解决:

  • 拆目录(hash 分桶)
  • 使用 xfs / btrfs
  • 避免单目录巨量文件

3️⃣ readdir 是 glibc 封装,不是 syscall

实际流程是:

readdir()
  -> getdents64()
  • glibc 会缓冲一批目录项
  • 但缓冲大小有限
  • 大量小文件时 syscall 次数仍多

✅ 更高效方式:

  • 直接 getdents64(高级用法)
  • 一次读几千个 entry

4️⃣ 文件系统不支持 d_type

如果:

ent->d_type == DT_UNKNOWN

说明:

  • 文件系统不支持文件类型
  • 必须 stat 才能知道是文件还是目录

✅ 支持 d_type 的:

  • ext4(默认)
  • xfs
  • btrfs

❌ 不支持:

  • 某些 NFS
  • 老文件系统

5️⃣ 目录缓存在内存外(cache miss)

  • 目录项不在 page cache
  • 要从磁盘读
  • HDD 特别慢

表现:

  • 第一次遍历慢
  • 第二次快(缓存热了)

三、为什么有人觉得“readdir 比 find 慢”

因为:

  • find 用 fstatat + 批量读取
  • find 避免不必要 stat
  • find 用 FTW / nftw

而你手写的可能:

  • 一个个 stat
  • 没利用 d_type

四、如何写出高效的目录遍历

✅ 推荐方式 1:用 d_type

while ((ent = readdir(dir))) {
    if (ent->d_type == DT_REG)
        // 普通文件
}

✅ 推荐方式 2:用 scandir(小目录)

struct dirent **list;
int n = scandir(path, &list, NULL, alphasort);

✅ 推荐方式 3:直接 getdents64(高性能)

  • 一次读大量 entry
  • 适合百万级目录

五、一句话总结

readdir 慢,通常不是 readdir 的锅,而是:

  • 目录太大
  • 每次都 stat
  • 文件系统不支持 d_type
  • 缓存未命中

如果你愿意,可以告诉我:

  • 用的文件系统(ext4 / xfs / nfs)
  • 目录大概多少文件
  • 是 C / Python / Shell

我可以直接给你最优遍历方案或代码示例。

0 踩