2010-12-29 2 views
18

Я пишу программу, проверяющую, является ли что-то файлом или является каталогом. Есть ли лучший способ сделать это, чем это?Проверка, является ли файл каталогом или просто файлом

#include <stdio.h> 

#include <sys/types.h> 
#include <dirent.h> 
#include <errno.h> 

int isFile(const char* name) 
{ 
    DIR* directory = opendir(name); 

    if(directory != NULL) 
    { 
    closedir(directory); 
    return 0; 
    } 

    if(errno == ENOTDIR) 
    { 
    return 1; 
    } 

    return -1; 
} 

int main(void) 
{ 
    const char* file = "./testFile"; 
    const char* directory = "./"; 

    printf("Is %s a file? %s.\n", file, 
    ((isFile(file) == 1) ? "Yes" : "No")); 

    printf("Is %s a directory? %s.\n", directory, 
    ((isFile(directory) == 0) ? "Yes" : "No")); 

    return 0; 
} 

ответ

36

Вы можете вызвать функцию stat() и использовать S_ISREG() макрос на st_mode поле stat структуры для того, чтобы определить, является ли ваши точки пути в обычный файл:

#include <sys/types.h> 
#include <sys/stat.h> 
#include <unistd.h> 

int is_regular_file(const char *path) 
{ 
    struct stat path_stat; 
    stat(path, &path_stat); 
    return S_ISREG(path_stat.st_mode); 
} 

Следует отметить, что существуют и другие типы файлов, кроме Регула r и directory, как устройства, трубы, символические ссылки, сокеты и т. д. Возможно, вы захотите принять их во внимание.

+4

При рассмотрении случаев symlink используйте lstat() вместо stat(), поскольку он не соответствует символической ссылке. – Sparky

+3

Существует, по крайней мере, хорошее обсуждение в [Проверка наличия каталога] (http://stackoverflow.com/questions/3828192/checking-if-a-directory-exists-in-unix-system-call/), где ' stat() 'и' lstat() ', а также полный набор типов файлов POSIX. Я соблазн дублировать этот вопрос на этот вопрос. Код также должен проверять результат 'stat()' и обрабатывать ошибки соответствующим образом. –

+0

@ Джонатан, этот ответ действительно более совершенен, чем мой, и был опубликован за три месяца до моего, пять лет назад. И это не похоже на то, что мой собственный ответ исчезнет. Я вижу, что вы владеете Mjölnir в теге '[c]', поэтому благодарим вас за комментирование, прежде чем действовать в одностороннем порядке. Однако вы в конечном счете правы. Не беспокойтесь, делайте то, что вам нужно сделать :) –

4

Да, есть еще лучше. Проверьте stat или функция fstat

14

Используйте S_ISDIR макрос:

int isDirectory(const char *path) { 
    struct stat statbuf; 
    if (stat(path, &statbuf) != 0) 
     return 0; 
    return S_ISDIR(statbuf.st_mode); 
} 
+0

Вы забыли заполнить структуру 'statbuf' информацией. – RedX

+1

Это прекрасно работает как функция, stat выполняет заполнение самой информации. – ismail

+2

В идеале код будет проверять, что 'stat' работал:' if (stat (path, & statbuf)! = 0) return 0; '- потому что несуществующий объект не является каталогом, и если у вас нет разрешение 'stat()' it, оно также может не существовать (даже если сообщаемая ошибка связана с разрешениями). –

1

Обычно вы хотите выполнить эту проверку атомарно с использованием результата, поэтому stat() бесполезен. Вместо этого файл open() сначала будет доступен для чтения и используйте fstat(). Если это каталог, вы можете использовать fdopendir() , чтобы прочитать его. Или вы можете попробовать открыть его для записи для начала, и open не будет работать, если это каталог. Некоторые системы (POSIX 2008, Linux) также имеют расширение O_DIRECTORY до open, что делает отказ вызова, если имя не является каталогом.

Ваш метод с opendir() также хорош, если вам нужен каталог, но вы не должны его закрывать; вы должны идти вперед и использовать его.

Смежные вопросы