在 Linux 下,readdir(以及底层的 getdents / getdents64 系统调用)读取目录时性能“差”,通常不是函数本身慢,而是使用方式 + 文件系统特性 + 目录规模共同导致的。下面分层说明原因和常见误区。
readdir 本身并不慢readdir 只是 libc 对 getdents64 的封装:
readdir ≈ 一次或几次 getdents真正慢的是:
你“怎么用
readdir” + “目录里有什么”
while ((de = readdir(dir))) {
...
}
getdents✅ 本质:目录不是数据库
很多人这样写:
while ((de = readdir(dir))) {
stat(de->d_name, &st); // ❌ 灾难
}
问题:
readdir 只给名字stat 要查 inode → 可能磁盘 IO✅ 正确做法:
readdir + d_type(如果支持)statx 批量openat + getdents 自己控制| 文件系统 | readdir 性能 |
|---|---|
| tmpfs | 极快 |
| ext4 | 一般 |
| xfs | 较好 |
| NFS | 很慢 |
| overlayfs | 慢(多层合并) |
NFS / 网络文件系统最惨:
readdir 可能触发多次网络往返Linux 有目录项缓存:
readdir:慢(读磁盘)以下情况会失效:
ls 很慢?ls -l
等价于:
readdir + stat 每个文件
而:
ls
只 readdir,通常快很多
| 场景 | 原因 |
|---|---|
| 百万文件目录 | 线性遍历 |
| readdir + stat | 随机 IO |
| NFS 目录 | 网络延迟 |
| Docker 挂载目录 | overlay |
| 日志目录 | 文件爆炸 |
✅ 不要在一个目录放太多文件
✅ 避免 readdir + stat
d_typeopenat + getdents64✅ 使用更高效的接口
getdents64io_uring(高级)✅ 缓存结果
Linux 的
readdir性能差,不是函数慢,而是“目录被当成了数据库用”。
如果你愿意,可以:
ls / 服务 / 备份场景我可以直接帮你定位瓶颈。