Есть ли лучший способ, чем просто попытаться открыть файл?
int exists(const char *fname)
{
FILE *file;
if ((file = fopen(fname, "r")))
{
fclose(file);
return 1;
}
return 0;
}
c
filesystems
cross-platform
Дейв Маршалл
источник
источник
fopen()
/fclose()
заключается в том, что вы не сможете открыть файл для чтения, даже если он существует. Например,/dev/kmem
существует, но большинство процессов не может открыть его даже для чтения./etc/shadow
еще один такой файл. Конечно, обаstat()
иaccess()
полагаются на возможность доступа к каталогу, содержащему файл; все ставки отключены, если вы не можете сделать это (нет разрешения на выполнение для каталога, содержащего файл).if (file = fopen(fname, "r"))
даст предупреждение. Используйте круглые скобки в операторе ifif ((file = fopen(fname, "r")))
Ответы:
Посмотрите на
access()
функцию, найденную вunistd.h
. Вы можете заменить свою функцию наВы также можете использовать
R_OK
,W_OK
иX_OK
вместо тогоF_OK
чтобы проверить для чтения разрешения, разрешений на запись и выполнение разрешения (соответственно) , а не существование, и вы можете или любые из них вместе (т.е. проверить , как для чтения и разрешения записи с помощьюR_OK|W_OK
)Обновление : обратите внимание, что в Windows вы не можете использовать
W_OK
надежный тест для разрешения записи, так как функция доступа не учитывает DACL.access( fname, W_OK )
может вернуть 0 (успех), поскольку файл не имеет установленного атрибута только для чтения, но у вас все еще может не быть разрешения на запись в файл.источник
access()
взлома моего кода. Я перешел с DevC ++ на CodeBlocks, и он перестал работать. Так что это не безошибочно; +1 больше к @Leffler.access()
для проверки существования файла), но в программах SUID или SGID даже это может быть неверно. Если проверенный файл находится в каталоге, к которому не может получить доступ настоящий UID или реальный GID,access()
такой файл может не появиться, если он существует. Эзотерический и невероятный? Да.Используйте
stat
как это:и назовите это так:
источник
access()
также есть проблемы, и есть варианты, которые можно использовать для созданияaccess()
иstat()
работы с большими файлами (более 2 ГБ).stat
страдает от такой же уязвимости TOCTOU, какaccess
? (Мне не ясно, что было бы лучше.)stat()
иaccess()
страдают от уязвимости TOCTOU (так жеlstat()
, ноfstat()
безопасно). Это зависит от того, что вы собираетесь делать, в зависимости от наличия или отсутствия файла. Использование правильных опцийopen()
обычно является лучшим способом решения проблем, но может быть сложно сформулировать правильные варианты. См. Также обсуждения EAFP (Проще просить прощения, чем разрешения) и LBYL (Посмотри, прежде чем ты прыгнешь ) - см., Например, LBYL против EAFP в Java .Обычно, когда вы хотите проверить, существует ли файл, это потому, что вы хотите создать этот файл, если он не существует. Ответ Грэма Перроу хорош, если вы не хотите создавать этот файл, но он уязвим для состояния гонки, если вы это сделаете: другой процесс может создать файл между вами, проверив, существует ли он, и вы фактически открываете его, чтобы записать в него , (Не смейтесь ... это может иметь плохие последствия для безопасности, если созданный файл был символической ссылкой!)
Если вы хотите проверить существование и создать файл, если он не существует, атомарно, чтобы не было условий гонки, то используйте это:
источник
open(2)
(для Linux; страницы руководства вашей ОС могут отличаться), но он довольно уродлив и не может быть устойчивым к злоумышленнику.FILE*
вам необходимо использовать метод posixfdopen(fd,"flags")
для генерацииFILE*
Да. Использование
stat()
. Смотрите справочную страницу дляstat(2)
.stat()
потерпит неудачу, если файл не существует, в противном случае, скорее всего, удастся. Если он существует, но у вас нет доступа на чтение к каталогу, в котором он существует, он также потерпит неудачу, но в этом случае произойдет сбой любого метода (как вы можете проверить содержимое каталога, который вы можете не видеть в соответствии с правами доступа? Просто не можешь)О, как кто-то еще упоминал, вы также можете использовать
access()
. Однако я предпочитаюstat()
, так как, если файл существует, он сразу же получит много полезной информации (когда он последний раз обновлялся, насколько он велик, владелец и / или группа, которой принадлежит файл, права доступа и т. Д.).источник
access()
проверяет права доступа к файлу для файла, и они хранятся в inode для этого файла и не находятся в его записи каталога (по крайней мере для всех файловых систем, которые имеют структуры, подобные inode) , Так чтоaccess()
должен получить доступ к иноду точно так же, какstat()
и к нему. То, что вы говорите, справедливо, только если вы не проверяете какие-либо разрешения! И на самом деле в некоторых системахaccess()
даже реализовано поверхstat()
(например, glibc в GNU Hurd делает это таким образом), поэтому в первую очередь нет никакой гарантии.источник
(fopen_s(file, "sample.txt", "r"))
посколькуfopen()
считается устаревшим (или отключить устаревшие ошибки, но это не рекомендуется).fopen()
это стандартный C, он никуда не денется. Это только «устарело» от Microsoft. Не используйте,fopen_s()
если вам не нужен платформо-зависимый непереносимый код.Из справки Visual C ++ я бы предпочел
Также стоит отметить значения режима :
_access(const char *path,
int mode
)
00: только существование
02: разрешение на запись
04: разрешение на чтение
06: разрешение на чтение и запись
Так как вы
fopen
можете потерпеть неудачу в ситуациях, когда файл существует, но не может быть открыт по запросу.Изменить: Просто прочитайте пост Меки.
stat()
выглядит аккуратнее. Хо гул.источник
Вы можете использовать функцию realpath ().
источник
Я думаю, что функция access () , которая находится в,
unistd.h
является хорошим выбором дляLinux
(вы также можете использовать stat ).Вы можете использовать это так:
И вы получите следующий результат:
источник