C语言实现tree命令:匹配ASCII格式标准输出的问题求助
问题:实现与
tree命令完全一致的ASCII树形输出 我留意到社区里已经有不少关于树形目录打印的讨论,但我的需求更具体——要完全匹配LC_ALL=C tree -n --charset=ascii [options] [dirs]的输出格式。目前我写的C代码已经能完成基本的目录遍历和文件/目录计数,但层级间的管道符始终无法正确显示,想请教调整思路。
现有代码(省略选项处理与符号链接检查)
#include <ctype.h> #include <dirent.h> #include <fnmatch.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> #include <unistd.h> //Functions prototypes void printaTree(int, char *, int *, int *, int); void printTreeconPattern(int livello, char * pattern); //MAIN int main(int argc, char * argv[]) { int checkgetopt; char * pattern; char * optargvalue; int maxHeight; int checkHidden = 0; int indice; int dirsindex = 0; char ** directories; directories = malloc(argc * sizeof(char *)); for (indice = optind; indice < argc; indice++) { directories[dirsindex] = malloc(strlen(argv[indice]) * sizeof(char)); strcpy(directories[dirsindex], argv[indice]); dirsindex++; } int livello = 0; int i; int countfiles = 0; int countDirs = 0; if (dirsindex == 0) { printf("%s\n", "."); printaTree(livello, ".", &countfiles, &countDirs, checkHidden); } else { for (i = 0; i < dirsindex; i++) { printf("%s\n", directories[i]); printaTree(livello, directories[i], &countfiles, &countDirs, checkHidden); } } printf("\n%d directories, %d files\n", countDirs, countfiles); free(directories); return 0; } void printaTree(int livello, char * directory, int * filenum, int * dirnum, int hidden) { struct dirent ** dobjects; int numeroOggetti = scandir(directory, &dobjects, NULL, alphasort); if (numeroOggetti == -1) { perror("scandir"); } char pathnuovo[1024]; int i; int checkSym = 0; char * buf; for (i = 0; i < numeroOggetti; i++) { if ((strcmp(dobjects[i]->d_name, ".") == 0) || (strcmp(dobjects[i]->d_name, "..") == 0)) continue; if (hidden == 0) { if (dobjects[i]->d_name[0] == '.') { continue; } } //Print how Tree command would print: if (i != numeroOggetti - 1) { if (livello != 0) { printf("%*s", livello * 4 - 1, ""); } else { printf("%*s", livello, ""); } printf("|-- "); printf("%s\n", dobjects[i]->d_name); } else { if (livello != 0) { printf("%*s", livello * 4 - 1, ""); } else { printf("%*s", livello, ""); } printf("`-- "); printf("%s\n", dobjects[i]->d_name); } if (dobjects[i]->d_type == DT_REG) { (*filenum)++; } if (dobjects[i]->d_type == DT_DIR) { (*dirnum)++; livello = livello + 1; snprintf(pathnuovo, sizeof pathnuovo, "%s%s%s", directory, "/", dobjects[i]->d_name); printaTree(livello, pathnuovo, filenum, dirnum, hidden); livello = livello - 1; } } }
测试场景
测试目录结构
RootDIRname file1 file2 dir1 ├── file4 ├── dir2 │ ├── file6 │ └── file7 └── dir3 ├── file10 └── file11 file8 file9
我的代码输出
RootDIRname |-- file1 |-- file2 |-- dir1 |-- file4 |-- dir2 |-- file6 `-- file7 `-- dir3 |-- file10 `-- file11 |-- file8 `-- file9
标准tree命令的正确输出
RootDIRname |-- file1 |-- file2 |-- dir1 | |-- file4 | |-- dir2 | | |-- file6 | | `-- file7 | `-- dir3 | |-- file10 | `-- file11 |-- file8 `-- file9
问题核心与思路指导
你现在的核心问题是:递归遍历过程中,没有跟踪当前路径上每一层级是否还有未处理的兄弟节点,所以无法正确输出用于对齐的竖线|。这里给你几个关键调整思路:
添加层级状态跟踪参数
给printaTree函数增加一个状态数组(比如int *is_last),数组的第k位用来记录第k层的当前节点是否是该层的最后一个节点:1表示不是最后一个(后续还有兄弟节点),0表示是最后一个。动态生成前缀字符串
在打印每个节点之前,根据状态数组生成前缀:- 遍历当前层级之前的所有层级,对于每一层:
- 如果该层还有后续兄弟节点,输出
|(竖线加三个空格); - 如果是该层最后一个节点,输出
(四个空格);
- 如果该层还有后续兄弟节点,输出
- 最后再加上当前节点的标记:如果当前节点不是所在层的最后一个,输出
|--;如果是最后一个,输出--。
- 遍历当前层级之前的所有层级,对于每一层:
递归时更新与恢复状态
- 进入子目录递归前,先更新状态数组:把当前层级的状态设为
(i != numeroOggetti - 1)(即是否有后续兄弟节点); - 递归完成后,要恢复这个状态(因为其他兄弟节点的子目录不需要这个标记),或者在递归调用时传递状态数组的副本,避免修改父级的状态。
- 进入子目录递归前,先更新状态数组:把当前层级的状态设为
举个例子,当处理dir1下的dir2时,dir1不是根目录的最后节点,所以dir2的前缀开头会有| ,再加上自身的层级标记,就能和上层的dir1形成正确的竖线连接,复现tree命令的格式。
内容的提问来源于stack exchange,提问作者Luca9504
相关产品推荐
相关产品推荐

