#c #linux
#c #linux
Вопрос:
Я пытаюсь изучить программирование на C для выполнения рабочей задачи, и я поставил перед собой небольшой проект, который состоит из чтения дерева файлов, включая все подкаталоги, для получения информации о каждом файле.
Проблема, которую я не мог решить, заключается в том, как создать строку при печати всех каталогов, как это делает команда real tree.
и это мой пример кода:
enum { doSkip, isFile, isDir } testDir(char *path, char *name)
{
struct stat st_buf;
if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
return doSkip;
}
stat(path, amp;st_buf);
if (S_ISDIR(st_buf.st_mode))
return isDir;
return isFile;
}
void list(const char *path, int indentlevel)
{
DIR *dirp = opendir(path);
struct dirent *dentry;
char buf[1024];
if (!dirp) {
printf("%*sNo accessn",indentlevel,"");
return;
}
while ((dentry = readdir(dirp)) != NULL) {
sprintf(buf,"%s/%s", path, dentry->d_name);
switch (testDir(buf,dentry->d_name)) {
case doSkip:
/* do nothing */
break;
case isDir:
printf("%*s%s:n",indentlevel,"",dentry->d_name);
list(buf,indentlevel 4);
break;
case isFile:
printf("%*s%sn",indentlevel,"",dentry->d_name);
break;
}
}
closedir(dirp);
}
int main()
{
list(".", 0);
return 0;
}
пожалуйста, дайте мне какую-нибудь идею!
Комментарии:
1. Вам нужен список уровней отступов, есть несколько параллельных ветвей, нарисованных для чего-либо глубиной более одного подкаталога.
2. Единственное отличие, которое я вижу, заключается в том, что выходные данные из команды дерева сортируются. Поэтому, если вы хотите отсортировать свои результаты, просто поместите их в какой-нибудь контейнер, отсортируйте и распечатайте после этого. Если есть что-то еще, кроме сортировки, дайте мне знать.
3. как мне составить список уровней отступов? @tripleee
4. ну, я не думаю, что мне нужно сортировать эти результаты, я просто хочу нарисовать линию, как это делает команда real tree : ( @Klaus
5. Чтобы помочь вам понять, что происходит, когда что-то идет не так.
Ответ №1:
list(buf,indentlevel 4);
Вы должны изменить это на list(buf,indentlevel 1)
, потому что вы поднимаетесь только на один уровень. Таким образом, вы можете отслеживать уровни каталогов. Добавьте еще одну функцию для добавления дополнительных пробелов. Смотрите пример ниже:
void space(int level, int file)
{
int i;
for (i = 0; i < level 1; i )
printf("x0b3 "); // add the '│' character
if (file)
printf("x0c3x0c4 "); // add '├' and '─' characters
}
void list(const char *path, int indentlevel)
{
DIR *dirp = opendir(path);
struct dirent *dentry;
char buf[1024];
if (!dirp)
{
printf("%*sNo accessn",indentlevel,"");
return;
}
int i;
while ((dentry = readdir(dirp)) != NULL)
{
sprintf(buf,"%s/%s", path, dentry->d_name);
switch (testDir(buf,dentry->d_name))
{
case doSkip:
break;
case isDir:
space(indentlevel, 1);
putchar('n');
space(indentlevel, 0);
printf("[ %s ]n",dentry->d_name);
list(buf,indentlevel 1);
break;
case isFile:
space(indentlevel-1, 1);
printf("%sn",dentry->d_name);
break;
}
}
closedir(dirp);
}
Вот более сложная версия, она хранит данные в буфере, поэтому она может найти последнего дочернего элемента в папке и нарисовать правильный символ «квадратного края» для последнего элемента. Он по-прежнему печатает несколько дополнительных вертикальных линий, о которых нужно позаботиться.
//store directory information
typedef struct TT_dir
{
char* name;
int isdir;
int level;
int islast;
} T_dir;
//vector for holding lines of data
typedef struct TT_vector
{
T_dir *data;
int capacity;
int size;
} T_vector;
void vector_add(T_vector *pvec, char *buf, int isdir, int level)
{
if (pvec->size == pvec->capacity)
{
pvec->capacity = 16;
pvec->data = realloc(pvec->data, pvec->capacity * sizeof(T_dir));
}
char *duplicate = malloc(strlen(buf) 1);
strcpy(duplicate, buf);
pvec->data[pvec->size].name = duplicate;
pvec->data[pvec->size].isdir = isdir;
pvec->data[pvec->size].level = level;
pvec->data[pvec->size].islast = 0;
pvec->size ;
}
void list(const char *path, int level, T_vector *pvec)
{
DIR *dirp = opendir(path);
struct dirent *dentry;
char buf[4096];
if (!dirp)
{
printf("%*sNo accessn", level, "");
return;
}
int haschildren = 0;
while ((dentry = readdir(dirp)) != NULL)
{
sprintf(buf, "%s/%s", path, dentry->d_name);
switch (testDir(buf, dentry->d_name))
{
case doSkip:
break;
case isDir:
//show progress:
printf(".");
//add directory info to vector array
vector_add(pvec, dentry->d_name, 1, level);
//next dir...
list(buf, level 1, pvec);
haschildren = 1;
break;
case isFile:
//add directory info to vector array
vector_add(pvec, dentry->d_name, 0, level);
haschildren = 1;
break;
}
}
//needs this information for drawing the correct character
if (haschildren)
pvec->data[pvec->size - 1].islast = 1;
closedir(dirp);
}
int main()
{
T_vector vec;
vec.capacity = 0;
vec.size = 0;
vec.data = 0;
list(".", 0, amp;vec);
printf("n");
int i, k;
for (i = 0; i < vec.size; i )
{
if (vec.data[i].isdir)
{
for (k = 0; k < vec.data[i].level; k ) printf("x0b3 ");
printf("x0b3n");
for (k = 0; k < vec.data[i].level; k ) printf("x0b3 ");
printf(vec.data[i].islast ? "x0c0" : "x0c3");
printf("x0c4 %s:n", vec.data[i].name);
}
else
{
for (k = 0; k < vec.data[i].level; k ) printf("x0b3 ");
printf(vec.data[i].islast ? "x0c0" : "x0c3");
printf("x0c4 %sn", vec.data[i].name);
}
}
return 0;
}
Ответ №2:
Вам нужно понять, что printf не обязательно печатать полную строку. В отличие от некоторых других функций печати на других языках.
for(i=0;i<identlevel;i )
printf("-");
printf("[ %s ]n", dentry->dname);
Сделает свое дело.