温馨提示×

linux readdir为何丢文件

小樊
37
2026-09-23 23:07:07
栏目: 智能运维

在 Linux 下使用 readdir()(或 readdir_r())遍历目录时“丢文件”,通常不是内核真的丢了文件,而是用法或环境导致你没读到。常见原因如下:


1. 没有循环读完整个目录

最常见错误:

struct dirent *de = readdir(dir);
// 只读了一次

readdir() 每次只返回一个条目,必须循环:

struct dirent *de;
while ((de = readdir(dir)) != NULL) {
    // 处理 de
}

否则只会看到第一个文件。


2. 在遍历时修改了目录

如果在 opendir() 之后:

  • 删除文件
  • 创建文件
  • 重命名文件

可能导致:

  • 某些文件不被返回
  • 某些文件被返回两次
  • 新文件是否可见取决于文件系统

这是 POSIX 明确规定的未定义/实现相关行为。

✅ 正确做法:

  • 先读全目录,再改
  • 或改用 open() + getdents() 并自己处理

3. 文件名被截断(d_name 长度)

struct dirent 中:

char d_name[256];

这只是 占位大小,并不保证足够。在某些实现中(尤其老 glibc),长文件名可能被截断。

✅ 更安全:

  • 使用 readdir_r()(仍有限制)
  • 或直接用 getdents64()

4. 隐藏文件被忽略

你可能在代码里写了:

if (de->d_name[0] == '.') continue;

这会丢掉:

  • .
  • ..
  • 所有隐藏文件

5. 符号链接 / 挂载点问题

  • 符号链接本身不会被丢
  • 但如果遍历的是 挂载点,而你在另一个命名空间(容器、chroot)中,可能看到不同内容

6. 并发或 NFS 问题

在 NFS / 网络文件系统 上:

  • 目录内容可能不一致
  • 遍历中途文件发生变化
  • 缓存导致“看不到”

本地 ext4 / xfs 一般不会丢。


7. readdir 返回 NULL 被误判为结束

readdir() 返回 NULL 可能是:

  • 正常结束
  • 出错(errno 被设置)

正确写法:

errno = 0;
while ((de = readdir(dir)) != NULL) {
    ...
}
if (errno != 0) {
    perror("readdir");
}

8. 目录太大,buffer 不够(低级用法)

如果你直接用:

  • getdents()
  • 自己管理 buffer

buffer 太小会导致部分条目丢失。


推荐写法(安全示例)

DIR *dir = opendir(path);
if (!dir) { perror("opendir"); return; }

struct dirent *de;
errno = 0;
while ((de = readdir(dir)) != NULL) {
    if (strcmp(de->d_name, ".") == 0 ||
        strcmp(de->d_name, "..") == 0)
        continue;
    printf("%s\n", de->d_name);
}
if (errno != 0)
    perror("readdir");

closedir(dir);

如果你愿意

可以贴出:

  • 你的 readdir 代码
  • 文件系统类型(ext4 / NFS / overlay)
  • 是否并发修改目录

我可以精确判断是哪一种“丢文件”。

0 踩