Повторяющиеся каталоги в C - PullRequest
0 голосов
/ 06 февраля 2011

Я новичок в C и пытаюсь просмотреть все каталоги / файлы из текущего рабочего каталога и вывести их информацию.Проблема, с которой я сталкиваюсь и которую я не могу придумать, - это хороший способ ее решения: если в одной директории есть две папки, во второй раз путь создается неправильно.Например, если dir1 и dir2 находятся на одном и том же пути после того, как «/ что-то / dir1» завершено, путь должен стать «/ что-то / dir2», но становится «/ что-то / dir1 / dir2» из-за того, как я пишу вещи.Я думал о том, чтобы просто отследить предыдущий путь, но я не уверен, как это сделать без постоянного перезаписи каждого рекурсивного вызова.

Обновление: с тех пор я исправил исходную ошибкуи решил, что я опубликую свой новый код здесь.Уловка, о которой я не знал, была opendir ("."), А changeir ("..") фактически перевел бы период в полный текущий или предыдущий путь.Что касается замены операторов type = 8 и type = 4 на более читаемые операторы S_ISDIR (statbuf.st_mode) и S_ISREG (statbuf.st_mode), они, похоже, не работают вообще, в то время как операторы типа работают.Не уверен, что не так с синтаксисом и способом, которым я пытался их использовать.

Обновление 2: я решил проблему S_ISDIR / S_ISREG здесь - Как использовать макросы POSIX S_ISREG () и S_ISDIR ()?

#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <dirent.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

void helper(DIR *, struct dirent *, struct stat, char *, int);
void dircheck(DIR *, struct dirent *, struct stat, char *, int);

int main(int argc, char *argv[]){

  DIR *dip;
  struct dirent *dit;
  struct stat statbuf;
  char currentPath[FILENAME_MAX];
  int depth = 0; /*Used to correctly space output*/

  dip = opendir(".");
  getcwd(currentPath, FILENAME_MAX);

  while((dit = readdir(dip)) != NULL){

    /*Skips . and ..*/
    if(strcmp(dit->d_name, ".") == 0 || strcmp(dit->d_name, "..") == 0)
      continue;

    stat(currentPath, &statbuf);

    /*Checks if current item is of the type file (type 8)*/
    if(dit->d_type == 8)
      printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size);

    /*Checks if current item is of the type directory (type 4)*/
    if(dit->d_type == 4)
      dircheck(dip, dit, statbuf, currentPath, depth);

  }
  return 0;
}

/*Recursively called helper function*/
void helper(DIR *dip, struct dirent *dit, struct stat statbuf, char currentPath[FILENAME_MAX], int depth){
  int i = 0;
  dip = opendir(currentPath);

  while((dit = readdir(dip)) != NULL){

    if(strcmp(dit->d_name, ".") == 0 || strcmp(dit->d_name, "..") == 0)
      continue;

    stat(currentPath, &statbuf);

    if(dit->d_type == 8){
      for(i = 0; i < depth; i++)
        printf("    ");
      printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size);
    }

    if(dit->d_type == 4)
      dircheck(dip, dit, statbuf, currentPath, depth);

  }
}

void dircheck(DIR *dip, struct dirent *dit, struct stat statbuf, char currentPath[FILENAME_MAX], int depth){
  int i = 0;

  strcat(currentPath, "/");
  strcat(currentPath, dit->d_name);

  /*If two directories exist at the same levelt the path
    is built wrong and needs to be corrected*/
  if((chdir(currentPath)) == -1){
    chdir("..");
    getcwd(currentPath, FILENAME_MAX);
    strcat(currentPath, "/");
    strcat(currentPath, dit->d_name);

    for(i = 0; i < depth; i++)
      printf ("    ");
    printf("%s (subdirectory)\n", dit->d_name);
    depth++;
    helper(dip, dit, statbuf, currentPath, depth);
  }

  else{
    for(i =0; i < depth; i++)
      printf("    ");
    printf("%s (subdirectory)\n", dit->d_name);
    chdir(currentPath);
    depth++;
    helper(dip, dit, statbuf, currentPath, depth);
  }

}

Ответы [ 2 ]

4 голосов
/ 06 февраля 2011

Не нужно заново изобретать колесо. Если вы работаете в системе Unixy, библиотечная функция nftw (входящая в группу параметров XSI в POSIX, то есть почти универсально доступная) делает именно то, что вам нужно:

http://pubs.opengroup.org/onlinepubs/9699919799/functions/nftw.html

С другой стороны, если вы делаете это как учебное упражнение, или если у вас есть (довольно редкий) экземпляр, где nftw не будет соответствовать вашим потребностям (например, если вам нужно выполнить рекурсию каталога) из нескольких потоков одновременно) приступить к отладке вашего решения.

1 голос
/ 07 февраля 2011

Самое первое, что я хотел бы сделать, это изменить:

if(type == 4)

К этому:

if(S_ISDIR(statbuf.st_mode))

Подробнее см. Справочную страницу stat .

Во-вторых, похоже, что вы никогда не звоните closedir. Вам нужно бесплатно вещи.

В-третьих ... Вместо того, чтобы копировать ваш opendir / readdir код в двух местах, было бы полезно поместить эту избыточную работу в одну и ту же функцию.

И, наконец .. Выделение MAX_PATH в стеке при каждой рекурсии будет довольно большим. Возможно, вы захотите использовать malloc и realloc. Но, как упоминалось выше в @R .., вы должны попытаться повторно использовать эти буферы там, где можете. Для большого дерева каталогов это займет много места и будет дорогим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...