在 Linux 下,readdir()(以及 opendir() / readdir_r())用于遍历目录。如果你想要替代 readdir,常见有以下几种方案,取决于你的需求(性能、可移植性、编程语言、并发安全等)。
getdents / getdents64 系统调用(更底层、更快)readdir() 本质是对 getdents64 的封装。
#include <unistd.h>
#include <fcntl.h>
#include <sys/syscall.h>
#include <linux/dirent.h>
#include <stdio.h>
#define BUF_SIZE 4096
int main() {
int fd = open(".", O_RDONLY | O_DIRECTORY);
char buf[BUF_SIZE];
int n = syscall(SYS_getdents64, fd, buf, BUF_SIZE);
struct linux_dirent64 *dir;
for (int bpos = 0; bpos < n; bpos += dir->d_reclen) {
dir = (struct linux_dirent64 *)(buf + bpos);
printf("%s\n", dir->d_name);
}
close(fd);
}
⚠️ 注意:这是 Linux 特有,不可移植。
scandir(简化遍历)scandir() 内部用 readdir,但更方便。
#include <dirent.h>
#include <stdio.h>
int main() {
struct dirent **namelist;
int n = scandir(".", &namelist, NULL, alphasort);
for (int i = 0; i < n; i++) {
printf("%s\n", namelist[i]->d_name);
free(namelist[i]);
}
free(namelist);
}
✅ 优点:
❌ 缺点:
fts(递归遍历推荐)如果你的目标是递归遍历目录,用 fts 替代 readdir 更合适。
#include <fts.h>
#include <stdio.h>
int main() {
char *paths[] = {".", NULL};
FTS *fts = fts_open(paths, FTS_NOCHDIR, NULL);
FTSENT *ent;
while ((ent = fts_read(fts))) {
if (ent->fts_info == FTS_F)
printf("%s\n", ent->fts_path);
}
fts_close(fts);
}
✅ 适合:
nftw(标准库,遍历树)#include <ftw.h>
#include <stdio.h>
int cb(const char *path, const struct stat *st, int flag, struct FTW *ftw) {
printf("%s\n", path);
return 0;
}
int main() {
nftw(".", cb, 10, FTW_PHYS);
}
✅ POSIX 标准
✅ 支持深度限制
#include <filesystem>
for (auto &p : std::filesystem::directory_iterator("."))
std::cout << p.path() << "\n";
import os
for name in os.listdir("."):
print(name)
for entry in std::fs::read_dir(".").unwrap() {
println!("{}", entry.unwrap().file_name().to_string_lossy());
}
readdir?| 原因 | 推荐方案 |
|---|---|
| 性能差 | getdents64 |
| 线程不安全 | readdir_r(已废弃) / scandir |
| 递归复杂 | fts / nftw |
| 现代开发 | C++ std::filesystem |
| 跨平台 | 高级语言 API |
如果你能说一下:
我可以给你最合适的替代方案。