Как правильно использовать Try Except для открытия файла на чтение-запись или только на чтение?

Пишу класс, который в конструкторе инициализируется из файла (обертка над данными в файле). Файл нужно открывать на чтение и запись, если это возможно, а если нет, то только на чтение. Правильно ли будет воспользоваться такой конструкцией:

    constructor TMyDocument.Create(const AFileName: string);
    begin
      try
        FFile := TFileStream.Create(AFileName, fmOpenReadWrite or fmShareDenyWrite);
        Load(FFile);
      except
        on E: Exception do
          if (E is EFOpenError) and (GetLastError = ERROR_ACCESS_DENIED) then
          try
            FFile := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite);
            Load(FFile);
          except
            raise;
          end
          else
            raise;
      end;
    end;
  1. Нет цели обработать исключение так, чтоб создать пустой объект в случае невозможности открыть файл, и завершить конструктор без ошибок. Обработать исключение - задача для того кто будет вызывать конструктор.
  2. Есть ли смысл пробовать открыть файл через CreateFile() и обрабатывать код ошибки, или вполне приемлемо использовать TFileStream и try except? Дальнейшая загрузка идет через TStream.
  3. Есть ли смысл во вложенном блоке try except (где идет попытка открыть файл только на чтение)? Или будет достаточно:
    constructor TMyDocument.Create(const AFileName: string);
    begin
      try
        FFile := TFileStream.Create(AFileName, fmOpenReadWrite or fmShareDenyWrite);
        Load(FFile);
      except
        on E: Exception do
          if (E is EFOpenError) and (GetLastError = ERROR_ACCESS_DENIED) then
          begin
            FFile := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite);
            Load(FFile);
          end
          else
            raise;
      end;
    end;

--------- UPDATE -----------

По итогу пришел к вот такому решению:

constructor TMyDocument.Create(const AFileName: string);
begin
  try
    FFile := TFileStream.Create(AFileName, fmOpenReadWrite or fmShareDenyWrite);
  except
    on E: EFOpenError do
      if (GetLastError = ERROR_ACCESS_DENIED) then
        FFile := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite)
      else
        raise;
  end;
  Load(FFile);
end;

Ответы (1 шт):

Автор решения: dr. F.I.N.

Спасибо за помощь Kromster и user7860670. Действительно, GetLastError после вызова TFileStream.Create() может вернуть 0 в зависимости от многих условий.

constructor TMyDocument.Create(const AFileName: string);
var
  tmpHandle: Integer;
begin
  tmpHandle := FileOpen(AFileName, fmOpenReadWrite or fmShareDenyWrite);
  if (tmpHandle < 0) then
    if (GetLastError = ERROR_ACCESS_DENIED) then
    begin
      tmpHandle := FileOpen(AFileName, fmOpenRead or fmShareDenyWrite);
      if (tmpHandle < 0) then
        RaiseLastOSError;
    end
    else
      RaiseLastOSError;
  FFile := TFileStream.Create(tmpHandle);
  Load(FFile); // Create(FFile);
end;

Я счёл наиболее удачным решением отказаться от использования try except и создать TFileStream не через имя файла, а через handle, полученный через вызов CreateFile (в моём случае FileOpen - обертка из SysUtils).

→ Ссылка