温馨提示×

linux readdir有何限制

小樊
39
2026-10-23 05:13:08
栏目: 智能运维

在 Linux 下,readdir(以及相关的 opendir / readdir_r / getdents)用于读取目录内容,但它有一些使用限制和注意事项,常见如下:


1. 单次返回一项,不是“列表”

readdir 每次调用只返回一个目录项(struct dirent *),不能一次性拿到整个目录内容。需要循环调用:

while ((entry = readdir(dir)) != NULL) {
    ...
}

2. 返回的是相对文件名

readdir 返回的是目录内的文件名(如 "file.txt"),不是完整路径。
如果需要完整路径,需要自己拼接:

snprintf(path, sizeof(path), "%s/%s", dirpath, entry->d_name);

3. 不保证顺序

readdir 不保证返回顺序(通常不是字母序),不同文件系统可能不同。
如果需要排序,必须自己 sort。


4. 会包含 . 和 ..

目录中一定包含:

  • . 当前目录
  • .. 上级目录

通常需要手动跳过:

if (strcmp(entry->d_name, ".") == 0 ||
    strcmp(entry->d_name, "..") == 0)
    continue;

5. 不能用于修改目录结构

在遍历目录时:

  • 不能安全地在同一个目录中 rename / unlink 正在遍历的项
  • 可能导致:
    • 条目被跳过
    • 条目被重复读取

6. readdir 不是线程安全的(很重要)

非线程安全

  • readdir 使用 目录流内部缓冲区
  • 同一 DIR* 不能被多个线程同时使用

✅ 正确方式:

  • 每个线程使用自己的 DIR*
  • 或使用 readdir_r(已不推荐)

7. readdir_r 已被废弃

  • POSIX.1-2008 标记 readdir_r 为 obsolete
  • glibc 也建议直接用 readdir(在单线程上下文)

8. 文件类型不一定可靠

d_type 字段:

  • 并非所有文件系统都支持(如某些网络文件系统)
  • 可能返回 DT_UNKNOWN

安全写法:

if (entry->d_type == DT_UNKNOWN) {
    struct stat st;
    stat(path, &st);
}

9. 有文件数 / 性能限制

  • 目录项非常多时(几十万+):
    • readdir 会多次系统调用
    • 性能不如 getdents64
  • 深层递归遍历要注意栈深度

10. 只能读“目录”

  • 不能对普通文件调用 opendir
  • 必须对目录有 读权限 + 执行权限(x)

11. 符号链接只返回名字

  • readdir 不会自动解析符号链接
  • 是否跟随需要你自己 stat / lstat

总结一句话

readdir 简单、稳定,但慢、无序、线程不安全、不返回完整路径、不适合高并发或超大目录。

如果你有具体场景(比如递归遍历、并发扫描、超大目录),我可以给出更合适的方案(如 nftw、getdents64、std::filesystem 等)。

0 踩