Как правильно использовать 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;
- Нет цели обработать исключение так, чтоб создать пустой объект в случае невозможности открыть файл, и завершить конструктор без ошибок. Обработать исключение - задача для того кто будет вызывать конструктор.
- Есть ли смысл пробовать открыть файл через CreateFile() и обрабатывать код ошибки, или вполне приемлемо использовать TFileStream и try except? Дальнейшая загрузка идет через TStream.
- Есть ли смысл во вложенном блоке 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 шт):
Спасибо за помощь 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
).