Быстрее ли проверять существование файла до загрузки или улавливать исключение, если оно не существует?

Мне было рекомендовано использовать второй вариант try-except, но я также хотел бы знать, что думают другие: какая процедура из двух ниже (если таковая имеется) более эффективна по времени?

procedure LoadImage(img: TImage; filename: string);
begin
  if fileexists(filename) then
    img.Picture.Loadfromfile(filename)
  else
    img.Picture.Loadfromfile('default.jpg')
end;

или

procedure LoadImage(img: TImage; filename: string);
begin
  try
    img.Picture.Loadfromfile(filename)
  except
    img.Picture.Loadfromfile('default.jpg')
  end
end;

Ответ 1

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

Первое ясно в своих намерениях. Каждый может легко понять, что происходит.

Второй заставляет меня остановиться и пойти "Что...?"

Вы никогда не захотите, чтобы ваш код вызывал вторую реакцию.

Ответ 2

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

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

Ответ 3

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

  • Если первый файл существует, загрузите его, иначе загрузите второй. Если первый файл существует, но не может быть загружен, выведите сообщение об ошибке.
  • Если первый файл не может быть загружен, вернитесь ко второму.

Если вам нужна семантика 1) ваш первый код в порядке.

Если вам нужна семантика 2), то ни одна из них не является хорошей. Первый код не имеет семантики, потому что:

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

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

Итак, чтобы достичь второй семантики, я бы использовал:

procedure LoadImage(img: TImage; filename: string);
var success:boolean;
begin
  success := false;
  if FileExists(filename)
    then try
      img.Picture.LoadFromFile(filename);
      success := true;
    except
    end
  if not success
    then img.Picture.LoadFromFile('default.jpg');
end;

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

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

Вы также должны рассмотреть предложение более целенаправленного исключения. Одеяло, улавливающее все исключения, - плохой стиль. К сожалению, я не смог найти четкую спецификацию, исключения которой выбраны TPicture.LoadFromFile, поэтому я оставлю сейчас в объявлении обложки.