2009-03-16 2 views
2

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

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

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

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

+0

Ваш код является более или менее способом ANSI для этого, ничего плохого в этом. –

+0

... и он медленный :) –

ответ

3

Стандартное решение POSIX: access(), которое также находится в среде Windows, как _access().

Я предполагаю, что это slighly лучше fopen() + fclose(), потому что:

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

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

+0

Остерегайтесь того, что access() может сообщить вам, что вы не можете получить доступ к файлам в программах setuid, даже те файлы, которые fopen() откроют просто отлично: http://www.gnu.org/software/libtool/manual/libc/ Testing-File-Access.html – dmityugov

+0

Спасибо, расслабьтесь, не знали о доступе(), это то, что я искал. Расовые условия на самом деле не проблема в том, что я делаю :) dmityugov, спасибо большое за комментарий, я буду осторожен в этом! –

+1

Я думаю, что исходное решение, вероятно, предпочтительнее для доступа(), на самом деле. Возможно, что access() будет немного быстрее, чем fopen()/fclose(), но есть всевозможные краевые случаи (setuid, ACL или условия гонки), где access() на самом деле не скажет вам, можете ли вы прочитайте файл. –

1

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

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

+0

Мой комментарий к отзыву Майкла :) –

1

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

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

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

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

+0

Спасибо, однако это в основном решить, какой файл конфигурации будет загружен без серьезной реструктуризации кода. К счастью, это одноразовая операция при запуске сервера, поэтому она вряд ли потерпит неудачу. –

+0

Обратите внимание, что даже если вы хорошо проверяете права доступа к файлам через «stat()», например, если есть ACL в использовании, вы не узнаете, можно ли открыть файл, если вы не ищете их тоже. –

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