печать строки как команды дерева

#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);
  

Сделает свое дело.