Подтвердить что ты не робот

Когда можно проверить, существует ли файл?

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

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

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

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

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

4b9b3361

Ответ 1

Метод File.Exists существует, прежде всего, для проверки наличия файла, когда вы не собираетесь открывать файл. Например, тестирование на наличие файла блокировки, само существование которого вам что-то говорит, но содержание которого не имеет значения.

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

EDIT: Несмотря на то, что это связано с API.Net, он основан на базовом системном API. У Windows и Unix есть системные вызовы (т.е. CreateFile), которые используют эквивалент перечисления FileMode. Фактически в .Net(или Mono) значение FileMode просто передается в базовый системный вызов.

Ответ 2

В качестве общей политики методы типа File.Exists или такие свойства, как WeakReference.Alive или SomeConcurrentQueue.Count, не являются полезными в качестве средства обеспечения существования "хорошего" состояния, но могут быть полезны как средство для определения того, существует "плохое" состояние без какой-либо ненужной (и, возможно, контрпродуктивной) работы. Такие ситуации могут возникать во многих сценариях, связанных с блокировками (и файлами, поскольку они часто включают блокировки). Поскольку все процедуры, которые должны блокировать набор ресурсов, должны, когда это целесообразно, всегда приобретать блокировки этих ресурсов в последовательном порядке, может потребоваться получить блокировку на одном ресурсе, который, как ожидается, будет существовать до получения ресурса, который может или может не существовать. В таком сценарии, в то время как невозможно избежать возможности блокировки первого ресурса, не получить второго, а затем освободить первый замок без какой-либо полезной работы с ним, проверяя наличие второго ресурса до приобретение блокировки на первом позволит свести к минимуму ненужные и бесполезные усилия.

Ответ 3

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

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

FileInfo fi = new FileInfo(fullFilePath);

int attempts = maxAttempts;
do
{
    try
    {
        // Asking to open for reading with exclusive access...
        fs = fi.Open(FileMode.Open, FileAccess.Read, FileShare.None);
    }
    // Ignore any errors... 
    catch {}

    if (fs != null)
    {
        break;
    }
    else
    {
        Thread.Sleep(100);
    }
}
while (--attempts > 0);

Ответ 4

Один пример: вы можете проверить наличие файлов, которые вы не можете открыть (из-за, например, разрешений).

Другой, возможно, лучший пример: вы хотите проверить наличие файла устройства Unix. Но определенно не открывайте его; его открытие имеет побочные эффекты (например, open/close /dev/st0 будет перематывать ленту)

Ответ 5

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

Ответ 6

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

РЕДАКТИРОВАТЬ 2

Это было, по сути, слишком упрощенным, и я рекомендую вам увидеть ответ Стивена Мартина.

Ответ 7

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

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

Я бы предпочел не программировать по исключению.

Изменить

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

Я предпочел бы попытаться предотвратить исключения, а не использовать их для управления логикой.

Изменить

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

Ответ 8

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

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

Если я ожидаю, что файл существует, было бы правильно, что будет выбрано Exception. Обработка исключений должна информировать пользователя или выполнять восстановление. Мое мнение таково, что это приводит к более чистым кодам.

Защита файлов (т.е. не переписывающих (возможно, важных) файлов) отличается, в этом случае я всегда проверяю, существует ли файл, если фреймворк не делает этого для меня (думаю, SaveFileDialog)

Ответ 9

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

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

Ответ 10

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

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

Ответ 11

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

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

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

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

Ответ 12

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

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

Ответ 13

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

РЕДАКТИРОВАТЬ. При запуске может появиться логическое вращение.

  try
  {
       if (File.Exists("app.log"))
       {
           RotateLogs();
       }

       log = File.Open("app.log", FileMode.CreateNew );
  }
  catch (IOException)
  {
     ...another writer, perhaps?
  }
  catch (UnauthorizedAccessException)
  {
     ...maybe I should have used runas?
  }

Ответ 14

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

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

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

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

Ответ 15

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

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

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

Ответ 16

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

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

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

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

Ответ 17

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

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

Ответ 18

Ваша проблема может быть легко решена с помощью базовой компьютерной науки... читать на Семафоры.

(Я не хотел звучать как рывок, я просто указывал вам на простой ответ для общей проблемы).