在 Ubuntu(Linux)下,使用 opendir() 读取目录时,如果觉得性能不够好,可以从系统调用层面、文件系统层面、编程方式层面来优化。下面按实用程度给你总结一下。
opendir() 本身很轻量,真正慢的通常是:
readdir() 逐个读取(大量小文件时系统调用多)stat() 文件(这是最大的性能杀手)stat()很多人这样写:
while ((entry = readdir(dir)) != NULL) {
stat(entry->d_name, &st); // 很慢
}
✅ 改进:
d_type(仅某些文件系统支持,如 ext4):if (entry->d_type == DT_REG)
getdents() 替代 opendir/readdiropendir/readdir 是 glibc 封装,次数多时有开销。
✅ 更高效的方式(底层):
#include <sys/syscall.h>
#include <unistd.h>
syscall(SYS_getdents64, fd, buf, size);
适合:
⚠️ 可移植性差,但性能最好
scandir()(一次性读取)struct dirent **namelist;
int n = scandir(path, &namelist, NULL, alphasort);
优点:
缺点:
openat() + 缓存目录 fd避免在深层目录中反复拼接路径:
int dfd = openat(parent_fd, "subdir", O_RDONLY | O_DIRECTORY);
适合:
在 Ubuntu 上:
| 文件系统 | 目录性能 |
|---|---|
| ext4 | ✅ 很好 |
| xfs | ✅ 大目录更好 |
| btrfs | ❌ 大目录较慢 |
| NFS | ❌ 非常慢 |
✅ 建议:
opendir 在 NFS 上会非常慢,因为:
readdir 都是网络往返✅ 优化:
如果目录里有 10 万+ 文件,任何 API 都会慢。
✅ 架构优化:
/data/a/b/abc.txt
Linux 会自动缓存,但你可以:
# 查看
free -h
确保:
| 场景 | 推荐方式 |
|---|---|
| 普通程序 | opendir + readdir,不 stat |
| 大目录 | scandir 或 getdents64 |
| 服务器 | openat + 缓存 fd |
| 超大规模 | 改架构(分目录 / DB) |
如果你愿意,可以告诉我:
我可以直接给你针对性代码优化版本。