Когда можно проверить, существует ли файл? - PullRequest
35 голосов
/ 23 марта 2009

Файловые системы нестабильны. Это означает, что вы не можете доверять результату одной операции, чтобы он был действительным для следующей, даже если это следующая строка кода. Вы не можете просто сказать if (some file exists and I have permissions for it) open the file, и вы не можете сказать if (some file does not exist) create the file. Всегда существует вероятность того, что результат вашего условия if изменит между между двумя частями вашего кода. Операции различны: не атомарные.

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

Поэтому при нормальных обстоятельствах лучший способ - даже не пытаться проверить, существует ли файл или каталог. Вместо этого потратьте время на разработку исключений из файловой системы. В любом случае вы должны обработать эти исключения, так что это намного лучше использует ваши ресурсы. Несмотря на то, что исключения являются медленными, проверка существования файла требует дополнительной поездки на диск, и доступ к диску становится на намного медленнее. У меня даже есть хорошо проголосовавший ответ на этот счет в другом вопросе.

Но у меня есть некоторые сомнения. Например, в .Net, если это действительно всегда true, методы .Exists() не были бы в API в первую очередь. Также рассмотрите сценарии, в которых вы ожидаете, что вашей программе понадобится создать файл. Первый пример, который приходит на ум, касается настольного приложения. Это приложение устанавливает файл конфигурации пользователя по умолчанию в свой домашний каталог, и при первом запуске каждого пользователя приложение копирует этот файл в папку данных приложения этого пользователя. Ожидается, что файл не будет существовать при первом запуске.

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

Ответы [ 18 ]

0 голосов
/ 01 апреля 2009

Чтобы ответить на мой собственный вопрос (частично), я хочу расширить пример, который я использовал: файл конфигурации по умолчанию.

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

0 голосов
/ 23 марта 2009

Если вы обеспокоены тем, что кто-то другой удалит файл, возможно, вам следует внедрить какую-то систему блокировки. Например, я работал над кодом для C-News, сервера новостей Usenet. Поскольку многое из того, что он делал, могло происходить асинхронно, он «блокировал» файл или каталог, создавая временный файл, а затем жестко связывал его с файлом с именем «LOCK». Если ссылка не удалась, это означало бы, что какая-то другая версия программы писала в этот каталог, в противном случае она была бы вашей, и вы могли бы делать то, что вам нравится.

Отличная вещь в том, что большая часть программы написана на shell и awk, и это был очень переносимый механизм блокировки. Кроме того, файл блокировки будет содержать PID владельца, поэтому вы можете посмотреть на существующий файл блокировки, чтобы убедиться, что владелец все еще работает.

0 голосов
/ 23 марта 2009

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

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

В .Net спецификация для File.Exists не содержит никаких исключений, которые может вызвать метод, в отличие, например, от File.Open, в котором перечислено девять исключений, поэтому в первом случае проверка, конечно, меньше.

Даже если «Exists» возвращает true, вам все равно нужно обрабатывать исключения при открытии файла, как предполагает ссылка .Net.

0 голосов
/ 23 марта 2009

Как вы указали, всегда важно, что должна делать программа, если файл отсутствует. Во всех моих приложениях пользователь всегда может удалить файл конфигурации, и приложение создаст новый файл со значениями по умолчанию. Нет проблем. Я также отправляю свои приложения без конфигурационных файлов.

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

Что должно произойти, если файл отсутствует? Вы можете выполнить поиск файла или обработчик исключений, но реальный вопрос: что произойдет, если файл отсутствует? Или насколько важен файл для приложения. Я проверяю все время, прежде чем пытаться получить доступ к файлам поддержки для приложения. Дополнительно я делаю обработку ошибок, если файл поврежден и не может быть загружен.

0 голосов
/ 23 марта 2009

Различные приложения включают в себя встроенные веб-серверы. Для них характерно генерировать самозаверяющие сертификаты SSL при первом запуске. Простой способ реализовать это - проверить, существует ли сертификат при запуске, и создать его, если нет.

Теоретически, он может существовать для проверки и не существовать позже. В этом случае мы получим ошибку, когда попытаемся прослушать, но это может быть легко обработано и не имеет большого значения.

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

И на практике оба случая чрезвычайно маловероятны.

0 голосов
/ 23 марта 2009

Существует множество возможных приложений, которые вы вполне можете написать, что простого File.Exists более чем достаточно для этой работы. Если это конфигурационный файл, который будет использоваться только вашим приложением, вам не нужно излишне перегружать себя обработкой исключений.

Хотя "недостатки", которые вы указали при использовании этого метода, все действительны, это не значит, что они не являются приемлемыми недостатками в некоторых ситуациях.

0 голосов
/ 23 марта 2009

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

Что вам нужно сделать, это позвонить, чтобы получить доступ к файлу, поскольку он обычно указывает через какую-то ошибку, что файл не существует (если он действительно не существует). В .NET вам придется пройти через слой P / Invoke и использовать функцию API CreateFile. Если эта функция возвращает ошибку ERROR_FILE_NOT_FOUND, то вы знаете, что файл не существует. Если он успешно возвращается, у вас есть дескриптор, который вы можете использовать.

Суть в том, что это в некоторой степени атомарная операция, что в конечном итоге и является тем, что вы ищете.

Затем с помощью дескриптора вы можете передать его конструктору FileStream и выполнить свою работу над файлом.

0 голосов
/ 23 марта 2009

У нас есть диагностический инструмент, который должен собрать набор файлов, включая журнал установки. В зависимости от различных условий журнал установщика может находиться в одной из двух папок. Хуже того, в обеих этих папках могут быть разные версии журнала. Как инструмент находит правильный?

Это довольно просто, если вы проверите на существование. Если присутствует только один, захватите этот файл. Если два существует, найдите, который имеет самое позднее время модификации и захватите этот файл. Это просто нормальный способ делать вещи.

...