C: Проверка типа файла. Использование lstat() и макросов не работает
Я использую opendir(), чтобы открыть каталог, а затем readdir() и lstat(), чтобы получить статистику каждого файла в этом каталоге. Следуя этой странице, я написал код, который работает не так, как задумывалось. Он перечисляет все файлы в текущем каталоге, но не распечатывает, является ли файл обычным файлом, символической ссылкой или каталогом.
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
void main(){
char* folder="."; //folder to open
DIR* dir_p;
struct dirent* dir_element;
struct stat file_info;
// open directory
dir_p=opendir(folder);
// show some info for each file in given directory
while(dir_element = readdir(dir_p)){
lstat(dir_element->d_name, &file_info); //getting a file stats
puts(dir_element->d_name); // show current filename
printf("file mode: %d\n", file_info.st_mode);
// print what kind of file we are dealing with
if (file_info.st_mode == S_IFDIR) puts("|| directory");
if (file_info.st_mode == S_IFREG) puts("|| regular file");
if (file_info.st_mode == S_IFLNK) puts("|| symbolic link");
}
}
3 ответа
Я знаю, что это годы спустя, но для потомков вы делали это неправильно:
@alk был прав : поле st_mode содержит больше информации, например, тип файла, права доступа к файлу и т. д.
Чтобы извлечь тип файла, вы выполняете его поразрядно, в поле st_mode и в маске типа файла S_IFMT. Затем проверьте результат на то, что вам нужно. Это то, что делают макросы, упомянутые @Ernest Friedman-Hill. Swicth лучше подходит для комплексной проверки, т.е.
для простого случая:
if ((file_info.st_mode & S_IFMT)==S_IFDIR) puts("|| directory");
для комплексной проверки:
struct stat st;
...
switch (st.st_mode & S_IFMT) {
case S_IFREG:
puts("|| regular file");
break;
case S_IFDIR:
puts("|| directory");
break;
case S_IFCHR:
puts("|| character device");
break;
case S_IFBLK:
puts("|| block device");
break;
case S_IFLNK:
puts("|| symbolic link");
break;
case S_IFIFO:
puts("|| pipe");
break;
case S_IFSOCK:
puts("|| socket");
break;
default:
puts("|| unknown");
}
Есть набор макросов для интерпретации st_mode
, что сложнее, чем вы думаете. Используйте их вместо непосредственного исследования поля:
if (S_ISREG(file_info.st_mode))
// file is a regular file
else if (S_ISLNK(file_info.st_mode))
// ...
Есть также S_ISDIR
, S_ISSOCK
и еще несколько. Смотрите, например, здесь для информации.
Режим несет много информации.
Попробуйте следующий вид теста:
if (S_ISDIR(file_info.st_mode)) puts("|| directory");