在 Ubuntu(Linux)下,readdir 的性能优化通常取决于使用场景、目录规模、文件系统类型以及编程方式。下面从系统层、文件系统层、编程层三个角度系统说明如何优化。
readdir(及 readdir_r)本质是:
getdents / getdents64bufsize 影响)常见瓶颈:
stat 每个文件(最常见性能杀手)opendir + readdir + statdf -T
Linux 会自动缓存目录项(dentry):
cat /proc/sys/vm/vfs_cache_pressure
值越小,越倾向保留 cache(默认 100)
临时调整:
sysctl -w vm.vfs_cache_pressure=50
mount -t tmpfs tmpfs /mnt/tmp
readdir + stat 组合❌ 错误示例(极慢):
while ((ent = readdir(dir))) {
stat(ent->d_name, &st); // 每个文件一次 stat
}
✅ 优化方案:
scandirscandir(一次读取 + 排序)struct dirent **namelist;
int n = scandir(path, &namelist, NULL, alphasort);
优点:
缺点:
getdents64 直接调用(高级)绕过 glibc:
#include <sys/syscall.h>
#include <linux/dirent.h>
syscall(SYS_getdents64, fd, buf, size);
优点:
适合:
opendir 默认 buffer 较小:
int fd = open(path, O_RDONLY | O_DIRECTORY);
DIR *dir = fdopendir(fd);
或使用:
posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
避免单目录百万文件:
data/
├── 00/
├── 01/
├── ff/
例如:
hash = md5(name)
prefix = hash[0:2]
statx(减少 stat 成本)struct statx stx;
statx(AT_FDCWD, name, 0, STATX_BASIC_STATS, &stx);
优点:
find(已高度优化)find . -maxdepth 1 -type f
ls(内部使用 getdents)ls --color=never
适合:
| 方法 | 10万文件 | 100万文件 |
|---|---|---|
| readdir + stat | 很慢 | 不可用 |
| scandir | 快 | 内存爆炸 |
| getdents64 | 很快 | 推荐 |
| 分目录 | 极快 | 极快 |
✅ 最佳实践
如果你愿意,可以告诉我:
我可以给你具体代码示例或基准测试方案。