在 Linux 下使用 readdir(或 readdir_r、getdents)遍历目录时,如果目录很大或访问频繁,效率问题会比较明显。下面从原理 → 常见瓶颈 → 优化手段系统说明。
readdir 底层最终调用的是:
getdents / getdents64
常见瓶颈:
这是最常见、最致命的性能问题。
while ((entry = readdir(dir))) {
stat(entry->d_name, &st); // ❌ 极慢
}
✅ 优化方案:
d_type(如果支持)if (entry->d_type == DT_REG)
readdir 而不是 glob / opendir+scandirscandir:会一次性加载并排序,内存 & 时间开销大glob:更慢✅ 推荐:
DIR *dir = opendir(path);
while ((e = readdir(dir))) { ... }
getdents64 直接读取(高级)减少 libc 封装开销:
#include <sys/syscall.h>
syscall(SYS_getdents64, fd, buf, size);
适合:
umount / rm -rf 大目录✅ 提高命中率:
# 保持目录常驻
ls /bigdir >/dev/null
性能排序(大目录):
xfs ≈ ext4 > btrfs > nfs
✅ 大目录推荐:
dir_index)tune2fs -l /dev/sdX | grep features
getdents 在 NFS 上:
✅ 方案:
rsync 镜像适合多子目录结构:
/root
├── a/
├── b/
├── c/
✅ 每个子目录一个线程
❌ 不要多线程读同一个目录(锁竞争)
如果目录基本不变:
find /data -type f > index.txt
查询时:
适合“常变目录”:
inotifywait -m /dir
避免全量 readdir
| 语言 | 建议 |
|---|---|
| C | getdents64 |
| Python | os.scandir(不是 os.listdir) |
| Go | filepath.WalkDir |
| Rust | ignore crate |
Python 示例(快):
with os.scandir(path) as it:
for e in it:
if e.is_file():
...
| 方法 | 100万文件 |
|---|---|
| readdir + stat | 30s+ |
| readdir + d_type | 2s |
| getdents64 | 1s |
| 索引查询 | <10ms |
✅ 最高优先级:
如果你愿意,可以告诉我:
我可以给你针对性代码或架构方案。