opendir 函数本身无法实现递归目录遍历,需要结合 readdir、closedir 和 stat (或 lstat 避免符号链接问题) 函数,并使用递归调用来实现。以下是一个改进的 C 语言示例,它能够更稳健地处理目录遍历,包括符号链接:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <dirent.h> #include <sys/stat.h> #include <limits.h> // for PATH_MAX void list_directory_contents(const char *path) { DIR *dir; struct dirent *entry; struct stat path_stat; char full_path[PATH_MAX]; dir = opendir(path); if (!dir) { perror("opendir"); return; } while ((entry = readdir(dir)) != NULL) { if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { continue; } // 使用 snprintf 避免缓冲区溢出 if (snprintf(full_path, sizeof(full_path), "%s/%s", path, entry->d_name) >= sizeof(full_path)) { fprintf(stderr, "Path too long: %s/%s ", path, entry->d_name); continue; } if (lstat(full_path, &path_stat) == -1) { // 使用 lstat 处理符号链接 perror("lstat"); continue; } if (S_ISDIR(path_stat.st_mode)) { list_directory_contents(full_path); } else if (S_ISREG(path_stat.st_mode)) { // 只打印常规文件 printf("%s ", full_path); } else if (S_ISLNK(path_stat.st_mode)) { printf("Symbolic link: %s ", full_path); // 处理符号链接 } else { printf("Other file type: %s ", full_path); // 处理其他文件类型 } } closedir(dir); } int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "Usage: %s <directory> ", argv[0]); return EXIT_FAILURE; } list_directory_contents(argv[1]); return EXIT_SUCCESS; }
此版本改进之处:
- 错误处理: 更全面的错误处理,包括 opendir 和 lstat 的错误检查。
- 路径长度限制: 使用 snprintf 来防止潜在的缓冲区溢出,避免路径过长导致程序崩溃。
- 符号链接处理: 使用 lstat 代替 stat,可以正确处理符号链接,避免无限递归。
- 文件类型区分: 区分常规文件和其他文件类型,例如符号链接,提供更详细的信息。
这个程序仍然假设 PATH_MAX 是定义的,在某些系统中可能需要包含额外的头文件或使用其他方法来获取最大路径长度。 记住编译时需要链接 -lm (如果你的系统需要)。 例如:gcc your_file.c -o your_program -lm