遍历目录并打印一些信息
Iterate over directory and print some information
我想编写一个 C 程序,它将文件夹的路径作为参数并显示有关它包含的文件的一些信息。
到目前为止我已经写了这个:
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char** argv){
char* dir_path = argv[1];
char* dir_path_bar = strcat(dir_path, "/");
DIR* dir = opendir(dir_path);
for(struct dirent* entry = readdir(dir); entry != NULL; entry = readdir(dir)){
printf("Next entry is %s\n", entry->d_name);
char* entry_path = strcat(dir_path_bar, entry->d_name);
printf("%s\n", entry_path);
struct stat buf;
stat(entry_path, &buf);
printf("Its inode number is %s\n", entry->d_ino);
printf("Its inode number is %s\n", buf.st_ino);
printf("Its uid is %s\n", buf.st_uid);
printf("Its size is %s bytes\n", buf.st_size);
};
closedir(dir);
}
可以编译,但是 stat
调用给我一个 SEGFAULT。这是怎么回事?
两个问题:
您正在 附加 连续到输入 (argv[1]
) 参数,这是未定义的行为。您不能附加到 argv
.
的字符串
还使用未定义的 %s
打印整数值。 %
s 需要一个 char *
参数,但您想打印整数值。
您可以改为使用临时缓冲区并将其传递给 stat(2)
:
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <limits.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
if (argc != 2) {
printf("Usage: %s dir\n", argv[0]);
exit(1);
}
char* dir_path = argv[1];
DIR* dir = opendir(dir_path);
if (!dir) {
perror("opendir");
exit(1);
}
for(struct dirent* entry = readdir(dir); entry != NULL; entry = readdir(dir)) {
char entry_path[PATH_MAX] = {0};
int rc = snprintf(entry_path, sizeof entry_path, "%s/%s", dir_path, entry->d_name);
if ( rc < 0 || rc >= sizeof entry_path) {
fprintf(stderr, "Path truncated for '%s'\n", entry->d_name);
continue;
}
printf("Next entry is: %s\n", entry_path);
struct stat buf;
if (stat(entry_path, &buf) == 0) {
printf("Its inode number is %ju\n", (uintmax_t)entry->d_ino);
printf("Its inode number is %ju\n", (uintmax_t)buf.st_ino);
printf("Its uid is %jd\n", (intmax_t)buf.st_uid);
printf("Its size is %jd bytes\n", (intmax_t)buf.st_size);
} else {
perror("stat");
}
}
closedir(dir);
}
我还添加了一些错误检查。
正如其他人所提到的,您不能附加到 argv[1]
。您不能在循环内继续追加它。而且,您不能使用 %s
来输出数字。
这是您的代码,其中包含注释和修复的错误[使用 #if 0
显示旧代码]:
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int
main(int argc, char **argv)
{
char *dir_path = argv[1];
// NOTE/BUG: argv[1] has a fixed size you can't append to it
#if 0
char *dir_path_bar = strcat(dir_path, "/");
#else
char dir_path_bar[PATH_MAX];
strcpy(dir_path_bar,dir_path);
strcat(dir_path_bar,"/");
#endif
DIR *dir = opendir(dir_path);
#if 1
if (dir == NULL) {
perror(dir_path);
exit(1);
}
#endif
for (struct dirent *entry = readdir(dir); entry != NULL;
entry = readdir(dir)) {
printf("Next entry is %s\n", entry->d_name);
// NOTE/BUG: because you don't reset dir_path_bar, this just keeps appending
// to it
#if 0
char *entry_path = strcat(dir_path_bar, entry->d_name);
#else
char entry_path[PATH_MAX];
strcpy(entry_path,dir_path_bar);
strcat(entry_path,entry->d_name);
#endif
printf("\n");
printf("%s\n", entry_path);
struct stat buf;
stat(entry_path, &buf);
// NOTE/BUG: these need one or more of: %d/%ld/%lld (vs %s)
#if 0
printf("Its inode number is %s\n", entry->d_ino);
printf("Its inode number is %s\n", buf.st_ino);
printf("Its uid is %s\n", buf.st_uid);
printf("Its size is %s bytes\n", buf.st_size);
#else
printf("Its inode number is %ld\n", entry->d_ino);
printf("Its inode number is %ld\n", buf.st_ino);
printf("Its uid is %d\n", buf.st_uid);
printf("Its size is %ld bytes\n", buf.st_size);
#endif
};
closedir(dir);
return 0;
}
其他 2 个较早的答案中未显示是避免过度复制的好方法。
形成entry_path
时,只需要覆盖条目本身,而不是整个字符串。这对于一个长的预先固定的目录字符串变得很有价值。
dir_path_len = strlen(dir_path);
if (dir_path_len >= PATH_MAX - 1) { return EXIT_FAILURE; } // too long
char entry_path[PATH_MAX];
strcpy(entry_path, dir_path);
strcpy(entry_path + dir_path_len++, "/"); // Can use strcpy() here
DIR *dir = opendir(dir_path);
...
for (struct dirent *entry = readdir(dir); entry != NULL; entry = readdir(dir)) {
printf("Next entry is %s\n", entry->d_name);
entry_len = strlen(entry->d_name);
if (dir_path_len + entry_len >= PATH_MAX) {
continue;
// or
return EXIT_FAILURE; // too long
}
strcpy(path + dir_path_len, entry->d_name); // strcpy(), not strcat()
printf("\n%s\n", entry_path);
struct stat buf;
if (stat(entry_path, &buf) ...
...
我想编写一个 C 程序,它将文件夹的路径作为参数并显示有关它包含的文件的一些信息。
到目前为止我已经写了这个:
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char** argv){
char* dir_path = argv[1];
char* dir_path_bar = strcat(dir_path, "/");
DIR* dir = opendir(dir_path);
for(struct dirent* entry = readdir(dir); entry != NULL; entry = readdir(dir)){
printf("Next entry is %s\n", entry->d_name);
char* entry_path = strcat(dir_path_bar, entry->d_name);
printf("%s\n", entry_path);
struct stat buf;
stat(entry_path, &buf);
printf("Its inode number is %s\n", entry->d_ino);
printf("Its inode number is %s\n", buf.st_ino);
printf("Its uid is %s\n", buf.st_uid);
printf("Its size is %s bytes\n", buf.st_size);
};
closedir(dir);
}
可以编译,但是 stat
调用给我一个 SEGFAULT。这是怎么回事?
两个问题:
您正在 附加 连续到输入 (
argv[1]
) 参数,这是未定义的行为。您不能附加到argv
. 的字符串
还使用未定义的
%s
打印整数值。%
s 需要一个char *
参数,但您想打印整数值。
您可以改为使用临时缓冲区并将其传递给 stat(2)
:
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <limits.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
if (argc != 2) {
printf("Usage: %s dir\n", argv[0]);
exit(1);
}
char* dir_path = argv[1];
DIR* dir = opendir(dir_path);
if (!dir) {
perror("opendir");
exit(1);
}
for(struct dirent* entry = readdir(dir); entry != NULL; entry = readdir(dir)) {
char entry_path[PATH_MAX] = {0};
int rc = snprintf(entry_path, sizeof entry_path, "%s/%s", dir_path, entry->d_name);
if ( rc < 0 || rc >= sizeof entry_path) {
fprintf(stderr, "Path truncated for '%s'\n", entry->d_name);
continue;
}
printf("Next entry is: %s\n", entry_path);
struct stat buf;
if (stat(entry_path, &buf) == 0) {
printf("Its inode number is %ju\n", (uintmax_t)entry->d_ino);
printf("Its inode number is %ju\n", (uintmax_t)buf.st_ino);
printf("Its uid is %jd\n", (intmax_t)buf.st_uid);
printf("Its size is %jd bytes\n", (intmax_t)buf.st_size);
} else {
perror("stat");
}
}
closedir(dir);
}
我还添加了一些错误检查。
正如其他人所提到的,您不能附加到 argv[1]
。您不能在循环内继续追加它。而且,您不能使用 %s
来输出数字。
这是您的代码,其中包含注释和修复的错误[使用 #if 0
显示旧代码]:
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int
main(int argc, char **argv)
{
char *dir_path = argv[1];
// NOTE/BUG: argv[1] has a fixed size you can't append to it
#if 0
char *dir_path_bar = strcat(dir_path, "/");
#else
char dir_path_bar[PATH_MAX];
strcpy(dir_path_bar,dir_path);
strcat(dir_path_bar,"/");
#endif
DIR *dir = opendir(dir_path);
#if 1
if (dir == NULL) {
perror(dir_path);
exit(1);
}
#endif
for (struct dirent *entry = readdir(dir); entry != NULL;
entry = readdir(dir)) {
printf("Next entry is %s\n", entry->d_name);
// NOTE/BUG: because you don't reset dir_path_bar, this just keeps appending
// to it
#if 0
char *entry_path = strcat(dir_path_bar, entry->d_name);
#else
char entry_path[PATH_MAX];
strcpy(entry_path,dir_path_bar);
strcat(entry_path,entry->d_name);
#endif
printf("\n");
printf("%s\n", entry_path);
struct stat buf;
stat(entry_path, &buf);
// NOTE/BUG: these need one or more of: %d/%ld/%lld (vs %s)
#if 0
printf("Its inode number is %s\n", entry->d_ino);
printf("Its inode number is %s\n", buf.st_ino);
printf("Its uid is %s\n", buf.st_uid);
printf("Its size is %s bytes\n", buf.st_size);
#else
printf("Its inode number is %ld\n", entry->d_ino);
printf("Its inode number is %ld\n", buf.st_ino);
printf("Its uid is %d\n", buf.st_uid);
printf("Its size is %ld bytes\n", buf.st_size);
#endif
};
closedir(dir);
return 0;
}
其他 2 个较早的答案中未显示是避免过度复制的好方法。
形成entry_path
时,只需要覆盖条目本身,而不是整个字符串。这对于一个长的预先固定的目录字符串变得很有价值。
dir_path_len = strlen(dir_path);
if (dir_path_len >= PATH_MAX - 1) { return EXIT_FAILURE; } // too long
char entry_path[PATH_MAX];
strcpy(entry_path, dir_path);
strcpy(entry_path + dir_path_len++, "/"); // Can use strcpy() here
DIR *dir = opendir(dir_path);
...
for (struct dirent *entry = readdir(dir); entry != NULL; entry = readdir(dir)) {
printf("Next entry is %s\n", entry->d_name);
entry_len = strlen(entry->d_name);
if (dir_path_len + entry_len >= PATH_MAX) {
continue;
// or
return EXIT_FAILURE; // too long
}
strcpy(path + dir_path_len, entry->d_name); // strcpy(), not strcat()
printf("\n%s\n", entry_path);
struct stat buf;
if (stat(entry_path, &buf) ...
...