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