问题介绍
最近使用Linux C进行编程的时候,当递归读取目录的时候会发现stat函数一直再报错(No such file or directory),经过一晚上的修改bug,发现我的代码中的stat函数只能访问用户当前所在的路径下的文件(即’pwd‘命令所提示的目录)。
例如:此时我所在的路径为:/home/mrzhi/Desktop/Linux-网络编程/Unix_systems_programming/Chapter5_File_system
结果:可以发现该代码可以正确访问所在路径下的文件,但是该路径下的文件夹却无法递归访问。但是该代码中的opendir和reddir函数可以正确打开和读取该路径下的文件夹。但是却无法使用stat函数返回文件的属性。
问题分析
这里我们先查看一下stat函数的定义
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *statbuf);
/* These functions return information about a file, in the buffer pointed to by statbuf.
No permissions are required on the file itself, **but—in the case of stat(), fstatat(),
and lstat()—execute (search) permission is required on all of the directories in pathname that lead to the file.**
* stat() and fstatat() retrieve information about the file pointed to by pathname;
the differences for fstatat() are described below.
*/
可以发现其中有这样一句话:but——in the case of stat, fstatat(), and lstat() - execute (search) permission is required on all of the directories in pathname that lead to the file。
这句话的意思是路径名中指向该文件的所有目录都必须具有执行(搜索权限)。也就是我所在目录下的test必须具备执行或搜索权限。
错误原因:
只有文件为绝对路径的情况下,才可以获取文件的stat状态。而刚开始的代码中直接为./test/bbb.txt,此时pathname会直接访问根目录下的test/bbb.txt,但是我的根目录下没有这个文件,因此会报“No Such file or directory”的错误。要切记使用绝对路径。
代码示例
我的代码示例如下:
**// 这个一个使用opendir,readdir和closedir等对目录操作的函数
// 该程序显示的是目录中包含的文件名,其实这个目录的路径名被作为命令行参数传送
// note:ls命令会按照字母顺序对文件名进行排序,而readdir函数则按照起在目录文件中出现的顺序显示文件名
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include <limits.h>
#include <sys/stat.h>
int printDir (char *path) {
DIR *dr;
int ret;
struct dirent *direntp;
struct stat *statbuf; // struct stat 用来保存stat和lstat函数中返回的信息
// note: 如果statbuf使用指针,则需要使用malloc函数为其分配内存空间,不如直接使用statbuf(不加指针)方便
//printf("sizeof(struct stat) = %d\n", sizeof(struct stat));
// 使用opendir函数打开所指定的目录
dr = opendir(path);
if(dr == NULL) {
perror("Failed to open directory");
return -1;
}
// 打印目录中的文件
statbuf = (struct stat*)malloc(sizeof(struct stat));
while ( (direntp = readdir(dr)) != NULL) {
// fprintf(stderr, "打印文件: ");
// 调用stat函数查看文件的状态
fprintf(stderr, "%s", direntp->d_name);
/* 在该函数中,stat只能访问用户所在的当前目录-->当前的原因我也不清楚*/
ret = stat(direntp->d_name, statbuf);
if (ret == -1) {
//fprintf(stderr, "errno is %d\n", errno);
perror(" : Failed to get file status");
//return -1;
} else {
// 其中st_atim表示最后一次访问的时间,st_time表示最后一次数据修改的时间
// st_ctime表示最后一次文件状态改变的时间
// ctime返回的字符串会以换行符结束,因此可以不用\n
printf(" : last accessed at %s", ctime(&(statbuf->st_atim)) );
// 如果该文件是个目录,则递归打印目录中的文件
if (*direntp->d_name != '.' && S_ISDIR(statbuf->st_mode)) {
printf("***************************%s is directory!***********\n", direntp->d_name);
printDir(direntp->d_name);
printf("***************************%s ********************\n", direntp->d_name);
}
}
}
while (direntp == NULL && errno == EINTR);
// note:使用完毕后一定要关闭目录
closedir(dr);
}
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s dir\n", argv[1]);
return -1;
}
//printf("%s\n", argv[1]);
int ret = printDir(argv[1]);
return 0;
}**
修改后的代码:
只有文件为绝对路径的情况下,才可以获取文件的stat状态。因此这里对printDir函数中的while部分代码进行修改即可。
// 打印目录中的文件
while ( (direntp = readdir(dr)) != NULL) {
// fprintf(stderr, "打印文件: ");
fprintf(stderr, "%s", direntp->d_name);
char buf[1024] = {0};
sprintf(buf, "%s/%s", path, direntp->d_name);
// 调用stat函数查看文件的状态
/* 在该函数中,stat只能访问用户所在的当前目录-->是路径的问题, 需要绝对路径才可以访问*/
ret = stat(buf, &statbuf);
if (ret == -1) {
perror(" : Failed to get file status");
//return -1;
} else {
// 其中st_atim表示最后一次访问的时间,st_time表示最后一次数据修改的时间
// st_ctime表示最后一次文件状态改变的时间
// ctime返回的字符串会以换行符结束,因此可以不用\n
printf(" : last accessed at %s", ctime(&statbuf.st_atim) );
// 如果该文件是个目录,则递归打印目录中的文件
if (*direntp->d_name != '.' && S_ISDIR(statbuf.st_mode)) {
// 当递归打印目录的时候,需要指定绝对路径,此时为 ./test
//sprintf(buf + strlen(buf), "/%s", direntp->d_name);
printf("***************************%s is directory!***********\n", buf);
printDir(buf);
printf("***************************%s ********************\n", buf);
}
}
}
note:以上问题是我在编程的时候遇到的,解决方法为经过百度和差异相关文献(由于本人水平有限,可能解答有错误)。如有错误之处,请多多指正并谅解。