Проверка возможности открытия файла с помощью переносимого C

Я хотел бы быстро проверить, можно ли открыть файл. Он должен быть написан на переносимом C или, по крайней мере, для работы в системах Win32 и POSIX. #ifdef допустимы.

Я пытаюсь избежать этого:

int openable(const char*filename) {
    FILE *f = fopen(filename,"r");
    if (!f)
        return 0; /* openable */
    fclose(f);
    return 1; /* not openable */
}

Из того, что я могу сказать, stat() в своей простейшей форме можно использовать для проверки существования файла, но не для проверки того, действительно ли он открывается.


person Ivan Vučica    schedule 16.03.2009    source источник
comment
Ваш код более или менее соответствует ANSI, в этом нет ничего плохого.   -  person Robert Gould    schedule 16.03.2009


Ответы (3)


Стандартное решение POSIX — access(), которое также присутствует в среде выполнения Windows как _access().

Думаю, это немного лучше, чем fopen()+fclose(), потому что:

  • Это известное, стандартное решение проблемы проверки файла на наличие прав доступа
  • Вероятно, это быстрее, с меньшими затратами памяти.

Конечно, он так же чувствителен к условиям гонки, как и любой другой способ проведения такого теста. В некотором смысле, единственный безопасный способ узнать, доступен ли файл для чтения, — это открыть его и попытаться прочитать, не закрывая его в промежутках. Даже в этом случае вам, конечно, все равно нужно следить за «неожиданным» EOF. Ввод/вывод затруднен.

person unwind    schedule 16.03.2009
comment
остерегайтесь, что access() может сказать вам, что вы не можете получить доступ к файлам в программах с setuid, даже те файлы, которые fopen() будут открываться нормально: gnu.org/software/libtool/manual/libc/Testing-File-Access.html - person dmityugov; 16.03.2009
comment
Спасибо, отмотайте, не знал про access(), это то, что я искал. Условия гонки не особо проблема в том, что я делаю :) dmityugov, большое спасибо за комментарий, я буду осторожен с этим! - person Ivan Vučica; 16.03.2009
comment
Я думаю, что исходное решение, вероятно, предпочтительнее, чем access(). Возможно, что access() будет немного быстрее, чем fopen()/fclose(), но есть всевозможные пограничные случаи (setuid, ACL или условия гонки), где access() на самом деле не скажет вам, можете ли вы прочитать файл. - person Mark Bessey; 16.03.2009

Есть много факторов, которые вам нужно проверить, прежде чем вы узнаете, что файл «открывается», и пытаться проверить их все кросс-платформенным способом было бы глупо.

Я думаю, что то, что вы делаете сейчас, проще и безопаснее. Однако помните, что только потому, что файл "открывается" сейчас, не означает, что он останется открытым, когда вы его действительно откроете. Ничто не мешает ему измениться за это время.

person MattJ    schedule 16.03.2009
comment
Мой комментарий к ответу Майкла :) - person Ivan Vučica; 16.03.2009

Я думаю, что то, что у вас есть, вероятно, так же хорошо, как вы получите (хотя ваши комментарии обратны тому, что они должны быть). Есть много вещей, которые могут помешать открытию файла: разрешения, что-то еще, удерживающее его открытым, нехватка ресурсов и т. д.

Чтобы точно пройти все эти проверки, вы можете просто открыть эту штуку.

Однако также обратите внимание, что в большинстве систем то, что вы возвращаете, может быть ложью для вызывающей стороны — к тому времени, когда вы возвращаете вызывающей стороне указание о том, можно ли открыть файл или нет, состояние систем может измениться ( что-то, что держало файл открытым исключительно, может, например, закрыть его). Таким образом, единственный по-настоящему эффективный способ для приложения узнать, могут ли они открыть и использовать файл, — это просто открыть и использовать файл (и обработать любые сбои).

Другими словами, если вы вернете вызывающему абоненту 'true', он может попытаться открыть файл, но это все равно может завершиться ошибкой.

person Michael Burr    schedule 16.03.2009
comment
Спасибо, однако это в основном для того, чтобы решить, какой файл конфигурации будет загружен без серьезной реструктуризации кода. К счастью, это одноразовая операция во время запуска сервера, поэтому вероятность ее сбоя невелика. - person Ivan Vučica; 16.03.2009
comment
Обратите внимание, что даже если вы хорошо проверите права доступа к файлам с помощью 'stat()', например, если используются списки управления доступом, вы не узнаете, можно ли открыть файл, если не будете их искать. - person Jonathan Leffler; 16.03.2009