Почему File.Exists () намного медленнее, когда файл не существует? - PullRequest
19 голосов
/ 09 февраля 2010

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

это правда?

Это не имеет смысла для меня.

Ответы [ 5 ]

42 голосов
/ 09 февраля 2010

File.Exists ловит исключения. Затраты на создание и захват исключения могут привести к снижению производительности.

File.Exists работает так:

Чтобы проверить, существует ли файл, он пытается открыть файл ... если выброшено исключение, файл не существует.

Этот процесс медленнее, чем открытие файла, и исключение не выдается (когда файл существует).

32 голосов
/ 09 февраля 2010

File.Exists также создает права доступа CLR перед проверкой, существует ли файл для файла. Альтернатива (хотя я не пробовал на производительность) - PathFileExists , если вы делаете много проверок:

[DllImport("Shlwapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
private extern static bool PathFileExists(StringBuilder path);

void Exists()
{
    // A StringBuilder is required for interops calls that use strings
    StringBuilder builder = new StringBuilder();
    builder.Append(@"C:\test.txt");
    bool exists = PathFileExists(builder);
}
10 голосов
/ 09 февраля 2010

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

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

3 голосов
/ 09 февраля 2010

Я выполнил следующий тест, и, по крайней мере, на моем ПК времена примерно такие же:

  static void TestExists()
     {
     Stopwatch sw = Stopwatch.StartNew();

     for ( int i = 0; i < 1000; i++ )
        {
        if ( !File.Exists( @"c:\tmp\tmp" + i.ToString() + ".tmp" ) )
           Console.WriteLine( "File does not exist" );
        }
     Console.WriteLine( "Total for exists: " + sw.Elapsed );

     sw = Stopwatch.StartNew();
     for ( int i = 0; i < 1000; i++ )
        {
        if ( File.Exists( @"c:\tmp\tmp_" + i.ToString() + ".tmp" ) )
           Console.WriteLine( "File exists" );
        }
     Console.WriteLine( "Total for not exists: " + sw.Elapsed );
     }

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

Total for exists: 00:00:00.0717181
Total for not exists: 00:00:00.0824266

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

Total for exists: 00:00:02.4028708
Total for not exists: 00:00:00.6910531
0 голосов
/ 09 февраля 2010

Файл и все его методы обычно работают с дескрипторами файлов Windows.

Если вы делаете много проверок, вы должны использовать:

FileInfo fiInfo = new FileInfo(@"c:\donotexists");
if (fiInfo.Exists)
    return true;

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...