2016-06-20 5 views
1

У меня возникли проблемы с попыткой реализовать что-то вроде ls -R на C. Дело в том, что мне нужно, чтобы список рекурсивно отображал все, начиная с заданного каталога, а затем делал материал с этими обычными файлами, которые я получаю из списка , Это то, что я до сих пор:Рекурсивный листинг

void ls(char* path){ 
    DIR *directory; 
    struct dirent *filei; 
    struct stat stats; 
    directory = opendir(path); 
    if (directory != NULL) 
    { 
     while ((filei=readdir(directory))!=NULL){ 
      stat(filei->d_name, &stats);  
      printf(" %s\n", filei->d_name); 
      if (S_ISDIR(stats.st_mode)){ 
       char *buf = malloc(strlen(path)+strlen(filei->d_name)+2); 
       strcpy(buf,path); 
       strcat(buf,"/"); 
       strcat(buf,filei->d_name); 
       ls(buf); 
      } 
     } 
     closedir(directory); 
    } 
    else{ 
     printf("Error.\n");  
    } 
} 

Это не работает на всех, она показывает файлы, которые даже не в папке я работаю с. Любые мысли? Спасибо.

+1

Это обычная проблема при работе с файлами/каталогами. 'd_name' не полный путь. Таким образом, вы не можете 'stat', если только ваш текущий каталог не является тем, который содержит этот файл/каталог. 'opendir' не изменяет ваш текущий каталог. 'chdir' нужно вызвать перед вызовом' stat'. Или создать полное имя пути. – kaylum

+1

Вам также нужно отфильтровать записи '.' и' ..'. В противном случае вы закончите бесконечную рекурсию. – kaylum

+0

Это решает проблему бесконечной рекурсии, но я не могу заставить ее работать, разве я не строил полный путь уже с этим? 'char * buf = malloc (strlen (path) + strlen (filei-> d_name) +2);' 'strcpy (buf, path);' 'strcat (buf,"/");' 'strcat (buf, filei-> d_name); ' – Stieg

ответ

1

Следующая переделки вашего кода вызывает stat() на полный путь к файлу, скачет над «» и «..» каталоги, фиксирует утечку памяти и добавляет только прикосновение обработки ошибок:

#define SEPARATOR "/" 

void ls(const char *path) 
{ 
    DIR *directory = opendir(path); 

    if (directory != NULL) 
    { 
     struct dirent *filei; 

     while ((filei = readdir(directory)) != NULL) 
     { 
      if (strcmp(filei->d_name, ".") == 0 || strcmp(filei->d_name, "..") == 0) 
      { 
       continue; 
      } 

      char *buffer = malloc(strlen(path) + strlen(filei->d_name) + strlen(SEPARATOR) + 1); 
      strcat(strcat(strcpy(buffer, path), SEPARATOR), filei->d_name); 

      struct stat stat_buffer; 

      if (stat(buffer, &stat_buffer) == 0) 
      { 
       printf("%s\n", buffer); 

       if (S_ISDIR(stat_buffer.st_mode)) 
       { 
        ls(buffer); 
       } 
      } 
      else 
      { 
       perror(NULL); 
      } 

      free(buffer); 
     } 

     closedir(directory); 
    } 
    else 
    { 
     perror(NULL);  
    } 
} 

Смотрите, если он работает лучше для вас.

3

Вы не должны переписываться на "." и "..". Вы рекурсивно переходите на один и тот же рельс или пойдите до плохо. Фильтр:

if (!strcmp(filei->d_name,".") && (!strcmp(filei->d_name,"..")) ls(buf); 

Вы также должны stat на полный путь:

char *buf = malloc(strlen(path)+strlen(filei->d_name)+2); 
strcpy(buf,path); 
strcat(buf,"/"); 
strcat(buf,filei->d_name); 
stat(buf, &stats); 
if (S_ISDIR(stats.st_mode)) { 
    if (!strcmp(filei->d_name,".") && (!strcmp(filei->d_name,"..")) { 
    ls(buf); 
    } 
}