Lazarus

Free Pascal => General => Topic started by: StephenMilner on January 14, 2022, 05:06:15 pm

Title: How to Capture a File Not Found Exception?
Post by: StephenMilner on January 14, 2022, 05:06:15 pm
I've got this snippet of code in a private class procedure which is called by the Class constructor.

When I deliberately pass a file that doesn't exist....

Code: Pascal  [Select][+][-]
  1.   try
  2.     try
  3.       AssignFile(Settings, SettingsFile);
  4.       Reset(Settings); // This generates the exception
  5.       //Statements
  6.     except
  7.       on e: EFileNotFoundException do // This code check fails and the else part is executed
  8.          writeln (DateToSTR(Date),':', TimeToSTR(Time),':', 'File Not Found :'+SettingsFile);
  9.       else
  10.         Raise; // This executes
  11.     end;
  12.   finally
  13.     try // I'm not sure this is the correct approach....
  14.       Close(Settings);
  15.     except
  16.       on E: Exception do writeln (DateToSTR(Date),':', TimeToSTR(Time),':', 'File Not Closed :'+SettingsFile); // This executes and writes to the console.
  17.     end;

The exception
Code: Pascal  [Select][+][-]
  1. EFileNotFoundException
doesn't appear to be the correct one.

The final exception raised is:
Code: Pascal  [Select][+][-]
  1. EInOutError: File not found

Should I use
Code: Pascal  [Select][+][-]
  1. EInOutError
instead of
Code: Pascal  [Select][+][-]
  1. EFileNotFoundException
?

How do I differentiate between other kinds of input/output errors in my exception handling?

I want code execution to terminate when the file isn't found.
Title: Re: How to Capture a File Not Found Exception?
Post by: GetMem on January 14, 2022, 05:20:43 pm
Old way:
Code: Pascal  [Select][+][-]
  1.   AssignFile(Settings, SettingsFile);
  2.   {$I-}
  3.   Reset(f);
  4.   {$I+}
  5.   if IOResult <> 0 then
  6.     Raise EFileNotFoundException.Create('File not found!');
  7.   //..


Modern way:
Code: Pascal  [Select][+][-]
  1.  if not FileExists(SettingsFile) then
  2.    Raise EFileNotFoundException.Create('File not found!');
  3.  //..
Title: Re: How to Capture a File Not Found Exception?
Post by: StephenMilner on January 14, 2022, 06:05:33 pm
Thanks.

Thanks that should simplify things
Title: Re: How to Capture a File Not Found Exception?
Post by: Thaddy on January 14, 2022, 06:27:51 pm
Why not call FileExists() and do away with EFileNotFoundException completely?
Exceptions should be just what they are:exceptions. They should be avoided in all situations where an exceptionless codepath is possible.
In this case EFileNotFoundException  is even a bit silly since FileExists() exists.. ;D
A good programmer should never burden his/hers code with superfluous exceptions.
Title: Re: How to capture a file not found exception?
Post by: Kays on January 14, 2022, 06:34:08 pm
Old way: […]
I don’t think the “old way” would use exceptions at all. Besides, IOResult (https://www.freepascal.org/docs-html/rtl/system/ioresult.html) does have many other results. I think the expected functionality of software (https://forum.lazarus.freepascal.org/index.php/topic,57841.html) is to produce reasonable and at least somewhat understandable error messages.
Code: Pascal  [Select][+][-]
  1. program nonExistentFileDemo(input, output, stdErr);
  2. uses
  3.         sysUtils; { ❗ automagically converts all RTEs to exceptions }
  4. const
  5.         FN = '/tmp/blabla';
  6. resourceString
  7.         errorInvalidPath = 'Error: some component in `%0:s` inaccessible';
  8. var
  9.         FD: text;
  10. begin
  11.         assign(FD, FN); { `assignFile` only in objFPC mode (←objPas unit) }
  12.         {$push}
  13.         {$IOChecks off}
  14.         reset(FD);
  15.         {$pop}
  16.         case IOResult of
  17.                 0:
  18.                 begin
  19.                         { no error }
  20.                 end;
  21.                 2:
  22.                 begin
  23.                         writeLn(stdErr, format(errorInvalidPath, [FN]));
  24.                         halt(-1);
  25.                 end;
  26.                 otherwise
  27.                 begin
  28.                         halt(-1);
  29.                 end;
  30.         end;
  31. end.

Why not call FileExists() and do away with EFileNotFoundException completely?
TOCTOU (https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use): The file gets deleted after the successful check, but just before you actually open it for reading.
Title: Re: How to Capture a File Not Found Exception?
Post by: GetMem on January 14, 2022, 06:57:26 pm
@Kays
Quote
I don’t think the “old way” would use exceptions at all. Besides, IOResult does have many other results
I agree with the exception part, I wouldn't even use an exception here, but that is not my concern.
By old I was referring to IOResult, when I learned to programming in the 90', it was already obsolete.
Title: Re: How to Capture a File Not Found Exception?
Post by: PascalDragon on January 14, 2022, 08:42:18 pm
The exception
Code: Pascal  [Select][+][-]
  1. EFileNotFoundException
doesn't appear to be the correct one.

The final exception raised is:
Code: Pascal  [Select][+][-]
  1. EInOutError: File not found

Should I use
Code: Pascal  [Select][+][-]
  1. EInOutError
instead of
Code: Pascal  [Select][+][-]
  1. EFileNotFoundException
?

Correct. If I/O exceptions are enabled it's always converted to an EInOutError.

How do I differentiate between other kinds of input/output errors in my exception handling?

You can get the I/O result code from the exception with EInOutError.ErrorCode (https://www.freepascal.org/docs-html/rtl/sysutils/einouterror.errorcode.html). For a list of error codes see here (https://www.freepascal.org/docs-html/current/user/userap4.html#x191-198000D).
TinyPortal © 2005-2018