我无法识别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
答案 0 :(得分:14)
dirp->d_name
是目录中文件的名称:例如"udpclient.c"
。因此,文件的全名为"/home/eipe/c/udpclient.c"
- 但您当前的工作目录为/home/eipe
,因此stat()
正在尝试访问不存在的"/home/eipe/udpclient.c"
。
您可以使用argv[1]
将工作目录更改为chdir()
,也可以在致电argv[1]
之前将stat()
添加到每个文件名中。
答案 1 :(得分:3)
请注意,POSIX 2008引入了fstatat()
和相关函数(系统调用),所有这些函数都以at
后缀区分为熟悉的函数名称。这些函数占用一个(或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()
和相关功能,您可以在不使用chdir()
的情况下使用相对路径名(这很危险;很难在不使用fchdir()
的情况下返回到您开始的位置),或者串联名称,如主要接受的答案中所示。为了便于携带,可能仍然建议使用连接 - 但我可以使用下面的代码在Mac OS X(10.10.1)和Linux(Ubuntu 14.04)上测试它。
开发成一个完整的程序(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
$