簡體   English   中英

使用chdir()而不是絕對路徑遍歷目錄

[英]Directory traversal with chdir() instead of with absolute paths

在“ Unix環境中的高級編程”這本書的第4章中,它涵蓋了文件和目錄,其中有一個代碼示例,旨在像ftw命令一樣並遍歷文件層次結構。 它使用指向絕對文件路徑的指針,以及帶有回調的遞歸函數來遍歷目錄,在此過程中使用對opendir()readdir()調用。

在一個練習中,要求讀者使用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);
}

我認為您不應該期望絕對路徑版本和chdir()版本之間在時間性能上有實質性差異。 而是,這兩個版本的優缺點如下:

  • 完整路徑名版本可能無法遍歷非常深的目錄結構,因為完整路徑名的長度最終會超過PATH_MAX chdir()版本沒有此問題。
  • chdir()版本操縱pwd,如果可以避免,通常會認為這是不好的作法:它不是線程安全的,最終用戶可能希望單獨使用它。 例如,在命令行上給定的文件名以及由程序的不同部分使用的文件名可能與用戶認為pwd的名稱有關,而當您更改pwd時它會中斷。
  • 如果沒有特別注意並且遍歷目錄結構時, chdir()版本在備份到更高目錄( chdir("..") )時可能會失去控制。 然后,在這種情況下,完整路徑名版本可能會以不同的方式中斷...

現代POSIX系統上可用的openat()系列功能可兼得兩全。 如果這些功能可用,則openat()以及fdopendir()fstatat()等……將為目錄遍歷提供一個非常好的實現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM