在 Linux 下使用 readdir() 读取目录时,符号链接(symbolic link)本身并不会被自动展开,readdir() 只是返回目录项(dirent),其中包含文件类型信息。是否“处理”符号链接,取决于你后续怎么做。
下面分几个层面说明。
readdir() 本身与符号链接readdir() 返回的是 struct dirent *:
struct dirent {
ino_t d_ino;
off_t d_off;
unsigned short d_reclen;
unsigned char d_type;
char d_name[256];
};
d_type 可以告诉你文件类型d_type 是:DT_LNK
示例:
#include <dirent.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
DIR *dir = opendir(argv[1]);
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
if (entry->d_type == DT_LNK) {
printf("symbolic link: %s\n", entry->d_name);
}
}
closedir(dir);
return 0;
}
✅ 这样你可以识别符号链接,但不会跟随它。
readdir()lstat()这些操作只看到符号链接本身
lstat(path, &sb);
// sb.st_mode 中 S_ISLNK(sb.st_mode) 为真
如果你用:
stat()open()access()那么会自动跟随符号链接,看到的是链接指向的目标。
struct stat sb;
stat(path, &sb); // 跟随符号链接
递归遍历目录时,如果不处理符号链接:
if (entry->d_type == DT_LNK)
continue;
struct stat sb;
lstat(path, &sb);
if (S_ISLNK(sb.st_mode)) {
stat(path, &sb);
if (S_ISDIR(sb.st_mode))
continue;
}
dev_t dev;
ino_t ino;
stat(path, &sb);
// 用 (dev, ino) 做已访问集合
如果想知道符号链接指向哪里:
char buf[PATH_MAX];
ssize_t len = readlink(path, buf, sizeof(buf) - 1);
buf[len] = '\0';
printf("links to: %s\n", buf);
⚠️ readlink() 不会追加 \0,需要手动处理。
| 操作 | 是否处理符号链接 |
|---|---|
readdir() |
只列出,不展开 |
lstat() |
看链接本身 |
stat() |
跟随链接 |
readlink() |
获取链接目标 |
| 递归遍历 | 建议显式跳过或防环 |
如果你愿意,我可以给你一个完整的“安全递归遍历目录”示例(C 语言),或者讲 fts / nftw 怎么自动处理符号链接。