在 Linux 下优化 readdir(目录遍历)效率,通常要从系统调用次数、缓存、文件系统特性、并发与数据结构几个层面来考虑。下面按实用程度整理。
getdents64 而不是 readdirreaddir 是 glibc 封装,默认一次只返回一个 entry,且有额外封装开销。
getdents64() 一次读取多个目录项示例思路:
#include <sys/syscall.h>
#include <linux/dirent.h>
syscall(SYS_getdents64, fd, buf, bufsize);
适合:大量文件目录(几万~上百万)
readdir_r / readdir64 注意线程安全readdir 不是线程安全的readdir_r(已废弃但稳定)或自己加锁不过线程安全 ≠ 更快
opendir + readdir 默认 buffer 较小(通常 32KB 左右)
自定义 buffer(glibc 扩展):
DIR *dir = opendir(path);
size_t size = 1 << 20; // 1MB
dirfd(dir);
// 实际仍需 getdents 控制 buffer
更好方式:直接用 getdents + 大 buffer(256KB~1MB)
很多人这样写:
while ((e = readdir(d))) {
stat(e->d_name, &st); // ❌ 很慢
}
优化方案:
d_type(readdir 返回)if (e->d_type == DT_REG) // 普通文件
statfstatat(AT_NO_AUTOMOUNT) 减少挂载点开销第一次遍历慢,第二次快,是因为:
优化:
drop_cachesvmtouch 预热目录元数据不同文件系统 readdir 性能差异巨大:
| 文件系统 | readdir 性能 |
|---|---|
| ext4 | 中等 |
| xfs | 好(大目录更优) |
| btrfs | 较差 |
| tmpfs | 极快 |
大目录(>10万文件):
❌ 一个目录 100 万个文件
✅ 分目录(hash / 日期)
例如:
/data/ab/cd/abcd1234
readdir 复杂度虽是 O(n),但:
如果只关心“存在性”:
比 readdir 快几个数量级
目录内部是串行的(内核锁),但:
root
├ a/
├ b/
├ c/
线程池并行 readdir
Linux 5.1+ 支持:
适合:
✅ 最有效的优化顺序:
stat 每个文件getdents64 + 大 buffer如果你愿意,可以告诉我:
stat我可以给你具体代码级优化方案。