当readdir()返回文件名时,stat()错误'No such file or directory'

我无法识别stat引发的错误。 下面的程序读取目录中的所有文件并打印文件名称:

DIR *dp; struct dirent *dirp; struct stat sb; if((dp = opendir(argv[1]))==NULL) { perror("can't open dir"); } while((dirp = readdir(dp))!=NULL) { if (stat(dirp->d_name, &sb) == -1) { perror("stat"); } printf("File name: %s \n",dirp->d_name); } 

示例输出:

 /home/eipe stat error: No such file or directory File name: copyofsample File name: a.out File name: . stat error: No such file or directory File name: udpclient.c File name: .. stat error: No such file or directory File name: client.c stat error: No such file or directory File name: ftpclient.c 

这里是内容:

 ls -l /home/eipe/c -rwxr-xr-x 1 eipe egroup 7751 2011-02-24 15:18 a.out -rw-r--r-- 1 eipe egroup 798 2011-02-24 13:50 client.c -rw-r--r-- 1 eipe egroup 15 2011-02-24 15:34 copyofsample -rw-r--r-- 1 eipe egroup 1795 2011-02-24 15:33 ftpclient.c -rw-r--r-- 1 eipe egroup 929 2011-02-24 13:34 udpclient.c 

dirp->d_name目录中文件的名称:例如"udpclient.c" 。 这个文件的全名是"/home/eipe/c/udpclient.c" – 但是你的当前工作目录是/home/eipe ,所以stat()试图访问"/home/eipe/udpclient.c" ,这是不存在的。

您可以使用chdir()将工作目录更改为argv[1] ,也可以在调用stat()之前将argv[1]到每个文件名。

请注意,POSIX 2008引入了fstatat()和相关函数(系统调用),所有这些都通过后缀来区分为熟悉的函数名称。 这些函数在renameat()的情况下需要一个(或两个)打开引用目录的文件描述符。 这意味着在支持fstatat()的系统上编码的另一种方法是:

 DIR *dp; struct dirent *dirp; struct stat sb; int dfd = open(argv[1], O_RDONLY); if (dfd == -1) { fprintf(stderr, "Failed to open directory %s for reading (%d: %s)\n", argv[1], errno, strerror(errno)); return -1; } if ((dp = opendir(argv[1]))==NULL) { perror("can't open dir"); return -1; } while ((dirp = readdir(dp)) != NULL) { if (fstatat(dfd, dirp->d_name, &sb, 9) == -1) { fprintf(stderr, "fstatat(\"%s\") failed (%d: %s)\n", dirp->d_name, errno, strerror(errno)); } printf("%-20s %s\n", "File name:", dirp->d_name); } 

使用fstatat()和相关函数可以使用相对path名,而不使用chdir() (这是危险的,很难返回到你开始的地方而不使用fchdir() ),或者连接主要接受的答案。 为了便于携带,无论如何可能还是build议使用串联 – 但是我可以使用下面的代码在Mac OS X(10.10.1)和Linux(Ubuntu 14.04)上testing它。

开发成一个完整的程序( test-fstatat.c ):

 #define _XOPEN_SOURCE 700 #include <dirent.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <unistd.h> int main(int argc, char **argv) { if (argc < 2) { fprintf(stderr, "Usage: %s directory [...]\n", argv[0]); return -1; } for (int i = 1; i < argc; i++) { DIR *dp; struct dirent *dirp; struct stat sb; int dfd = open(argv[i], O_RDONLY); if (dfd == -1) { fprintf(stderr, "Failed to open directory %s for reading (%d: %s)\n", argv[i], errno, strerror(errno)); continue; } if (fstat(dfd, &sb) != 0 || !S_ISDIR(sb.st_mode)) { errno = ENOTDIR; fprintf(stderr, "%s: %d %s\n", argv[i], errno, strerror(errno)); continue; } if ((dp = opendir(argv[i]))==NULL) { perror("can't open dir"); continue; } printf("%-20s %s\n", "Directory:", argv[i]); while ((dirp = readdir(dp)) != NULL) { if (fstatat(dfd, dirp->d_name, &sb, 0) == -1) { fprintf(stderr, "fstatat(\"%s\") failed (%d: %s)\n", dirp->d_name, errno, strerror(errno)); continue; } printf("%-20s %s\n", "File name:", dirp->d_name); } closedir(dp); close(dfd); } return 0; } 

样品运行:

 $ test-fstatat ~/bin/JLSS-Dist/RCS ../src/sqltools/idsmon Directory: /Users/jleffler/bin/JLSS-Dist/RCS File name: . File name: .. File name: bomrelease.pl,v File name: chkbodlst.sh,v File name: chkmsdnmd.sh,v File name: chksumtool.pl,v File name: jdcrelease.sh,v File name: JLSS-Dist.mk,v File name: jlss.sh,v File name: mkbod.sh,v File name: mkmsd.sh,v File name: mknmd.sh,v File name: msd.create.sh,v File name: MSD.sh,v File name: prodverstamp.sh,v File name: publictimestamp.sh,v File name: redonmd.sh,v Directory: ../src/sqltools/idsmon File name: . File name: .. File name: acsetup.sh File name: dumpdblflt File name: dumpdblflt.c File name: idsmon File name: idsmon.o File name: idspacket File name: idspacket.c File name: idspacket.o File name: idstest File name: idstest.c File name: idstest.o $