温馨提示×

centos readdir坑有哪些

小樊
46
2026-09-18 07:26:33
栏目: 智能运维

在 CentOS(本质是 Linux 的 readdir 系列调用) 里,readdir / readdir_r / scandir 确实有一些“坑”和容易踩雷的地方,尤其在高并发、大目录、跨版本、C/C++ 开发中很常见。下面按实际踩坑频率给你总结一下。


一、readdir 不是线程安全的(最常见坑)

现象

多线程同时调用同一个 DIR*:

DIR *dir = opendir(path);
readdir(dir); // ❌ 多线程共用

会导致:

  • 读到乱序
  • 读不全
  • 偶发崩溃(glibc 内部状态被破坏)

正确做法

  • 每个线程自己 opendir
  • 或用 readdir_r(但见下一条)

二、readdir_r 已被官方“不建议使用”

坑点

  • CentOS 7 上还能用
  • glibc 2.24+(CentOS 8 起)标记 deprecated
  • 未来版本可能直接移除

官方推荐

直接用 readdir(),但保证 一个 DIR 只被一个线程使用*


三、目录很大时性能暴跌(大目录坑)

现象

  • 目录里 几十万 / 上百万文件
  • readdir 非常慢
  • CPU 飙升

原因

  • ext4 / xfs 目录不是“数组”
  • readdir 是顺序遍历
  • 无法随机访问

解决思路

✅ 拆分目录(hash / 日期) ✅ 用数据库 / 对象存储 ✅ 避免 ls 大目录


四、readdir 不保证顺序(很多人误解)

误区

以为 readdir 是按文件名排序的

实际情况

  • 完全无序
  • 顺序依赖文件系统实现

✅ 需要排序要自己 sort


五、inode 复用导致“误判文件存在”

场景

struct dirent *de = readdir(dir);
de->d_ino == 0; // 某些网络文件系统

坑

  • NFS
  • FUSE
  • 某些特殊 fs 可能返回:
  • d_ino == 0
  • 重复 inode

六、d_type 并不总是可靠(隐藏大坑)

代码

de->d_type == DT_REG

坑点

  • NFS:d_type == DT_UNKNOWN
  • 老文件系统不支持

正确做法

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

七、readdir 之后文件名可能被覆盖(经典 bug)

错误代码

char *names[100];
struct dirent *de;
while ((de = readdir(dir))) {
    names[i++] = de->d_name; // ❌
}

原因

  • readdir 返回的是同一块静态内存
  • 下一次调用会覆盖

正确

names[i++] = strdup(de->d_name);

八、opendir 失败没检查(生产事故源)

DIR *dir = opendir(path);
readdir(dir); // path 不存在直接崩

✅ 必须:

if (!dir) {
    perror("opendir");
}

九、CentOS 版本差异坑

CentOS glibc 注意
6 2.12 readdir_r 安全
7 2.17 还能用
8+ 2.28+ readdir_r deprecated

十、mount 点 / 符号链接陷阱

  • readdir 不解析符号链接
  • mount --bind 可能导致:
    • 同一文件多次出现
    • 目录循环

推荐安全写法(CentOS 通用)

DIR *dir = opendir(path);
if (!dir) return;

struct dirent *de;
while ((de = readdir(dir))) {
    if (de->d_name[0] == '.') continue;

    if (de->d_type == DT_UNKNOWN) {
        // stat
    }
}
closedir(dir);

总结一句话

CentOS 上 readdir 最大的坑不是 API 本身,而是:线程安全、顺序、d_type、内存复用、目录规模。

如果你愿意,我可以:

  • 给你 C / C++ 安全目录遍历模板
  • 或针对 NFS / docker / k8s 场景 讲坑
  • 或对比 readdir vs scandir vs getdents

你现在是 C / C++ / Python / shell 场景?

0 踩