ファイルとディレクトリを扱っている本の「Unix 環境での高度なプログラミング」の第 4 章には、ftw
コマンドのようにファイル階層をたどることを目的としたコード サンプルがあります。絶対ファイル パスへのポインターと、コールバックを伴う再帰関数を使用して、プロセス内のopendir()
およびへの呼び出しを使用してディレクトリをトラバースreaddir()
します。
chdir()
同じタスクを実行し、2 つのプログラムの時間を比較するために、絶対パスを使用する代わりにファイル名を使用するよう読者に求める演習があります。を使用してプログラムを作成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);
}