2013-06-25 3 views
1

В главе 4 книги «Расширенное программирование в среде Unix», которая охватывает файлы и каталоги, есть образец кода, который должен быть как команда ftw и траверс файловая иерархия. Он использует указатель на абсолютный путь к файлу, а также рекурсивную функцию с обратным вызовом для перемещения по каталогу, используя вызовы opendir() и readdir().Обход каталога с помощью chdir() вместо абсолютных путей

Существует упражнение, в ходе которого читателям предлагается использовать chdir() и имена файлов вместо использования абсолютных путей для выполнения одной и той же задачи и для сравнения времени двух программ. Я написал программу с использованием chdir() и не заметил разницы во времени. Ожидается ли это? Я бы подумал, что дополнительный вызов chdir() добавит некоторые накладные расходы. Может быть, это относительно тривиальный призыв? Любое понимание было бы оценено.

Вот рекурсивная функция, используя абсолютные пути:

static int     /* we return whatever func() returns */ 
dopath(Myfunc* func) 
{ 
    struct stat  statbuf; 
    struct dirent *dirp; 
    DIR    *dp; 
    int    ret; 
    char   *ptr; 

    if (lstat(fullpath, &statbuf) < 0) /* stat error */ 
     return(func(fullpath, &statbuf, FTW_NS)); 
    if (S_ISDIR(statbuf.st_mode) == 0) /* not a directory */ 
     return(func(fullpath, &statbuf, FTW_F)); 

    /* 
     * It's a directory. First call func() for the directory, 
     * then process each filename in the directory. 
     */ 
    if ((ret = func(fullpath, &statbuf, FTW_D)) != 0) 
     return(ret); 

    ptr = fullpath + strlen(fullpath);  /* point to end of fullpath */ 
    *ptr++ = '/'; 
    *ptr = 0; 

    if ((dp = opendir(fullpath)) == NULL)  /* can't read directory */ 
     return(func(fullpath, &statbuf, FTW_DNR)); 

    while ((dirp = readdir(dp)) != NULL) { 
     if (strcmp(dirp->d_name, ".") == 0 || 
      strcmp(dirp->d_name, "..") == 0) 
       continue;  /* ignore dot and dot-dot */ 

     strcpy(ptr, dirp->d_name); /* append name after slash */ 

     if ((ret = dopath(func)) != 0)   /* recursive */ 
       break; /* time to leave */ 
    } 
    ptr[-1] = 0; /* erase everything from slash onwards */ 

    if (closedir(dp) < 0) 
     err_ret("can't close directory %s", fullpath); 

    return(ret); 
} 

А вот функция с моими изменениями:

static int     /* we return whatever func() returns */ 
dopath(Myfunc* func, char* path) 
{ 
    struct stat  statbuf; 
    struct dirent *dirp; 
    DIR    *dp; 
    int    ret; 

    if (lstat(path, &statbuf) < 0) /* stat error */ 
     return(func(path, &statbuf, FTW_NS)); 
    if (S_ISDIR(statbuf.st_mode) == 0) /* not a directory */ 
     return(func(path, &statbuf, FTW_F)); 

/* 
* It's a directory. First call func() for the directory, 
* then process each filename in the directory. 
*/ 
    if ((ret = func(path, &statbuf, FTW_D)) != 0) 
     return(ret); 

    if (chdir(path) < 0) 
     return(func(path, &statbuf, FTW_DNR)); 

    if ((dp = opendir(".")) == NULL)  /* can't read directory */ 
     return(func(path, &statbuf, FTW_DNR)); 

    while ((dirp = readdir(dp)) != NULL) { 
     if (strcmp(dirp->d_name, ".") == 0 || 
      strcmp(dirp->d_name, "..") == 0) 
       continue;  /* ignore dot and dot-dot */ 

     if ((ret = dopath(func, dirp->d_name)) != 0)   /* recursive */ 
       break; /* time to leave */ 
    } 
    if (chdir("..") < 0) 
     err_ret("can't go up directory"); 

    if (closedir(dp) < 0) 
     err_ret("can't close directory %s", fullpath); 

    return(ret); 
} 

ответ

1

Я не думаю, что вы должны ожидать существенную разницу производительности времени между абсолютным версии пути и версии chdir(). Скорее всего, плюсы и минусы обеих версий заключаются в следующем:

  • Полная версия путь не может быть в состоянии пройти очень глубокие структуры каталогов, так как длина полного пути в конечном счете превышает PATH_MAX. Версия chdir() не имеет этой проблемы.
  • Версия chdir() управляет pwd, который обычно считается плохой практикой, если вы можете его избежать: он не является потокобезопасным, и конечный пользователь может ожидать, что он останется в покое. Например, имена файлов, указанные в командной строке и используемые другой частью программы, могут быть относительно того, что, по мнению пользователя, было pwd, которое прерывается при его изменении.
  • Версия chdir() может выйти из-под контроля при резервном копировании в более высокий каталог (chdir("..")), если особая осторожность не будет предпринята и структура каталогов изменится во время прохождения. Затем снова полная версия путь может сломаться по-другому в этих условиях ...

openat() семейство функций, доступных на современных системах POSIX предлагают лучшее из обоих миров. Если эти функции доступны, openat() вместе с fdopendir(), fstatat() и т. Д. Делают для действительно приятной реализации каталогов, идущих.

+0

Спасибо за понимание и другие функции! – rsa