6

I'm using old style Pascal I/O routines and expect that calls to I/O functions that fail should raise an EInOutError. When I try this I do not see an exception raised and I have no clue why.

procedure TForm1.Button1Click(Sender: TObject);
//var i: integer;
begin
id:=(strtoint(Edit1.Text)-1)*4;

AssignFile(plik,'\klienci\'+linia_klient[id]+'.txt');
try
Reset(plik);
except
  on EInOutError do Rewrite(plik);
  end;
edit2.Text:=linia_klient[id+1];
edit3.Text:=linia_klient[id+2];
//ListBox1.Clear;
//ListBox1.Items.Add();
end;

Entire code:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Label1: TLabel;
    Edit1: TEdit;
    Button1: TButton;
    Label2: TLabel;
    Label3: TLabel;
    Edit2: TEdit;
    Edit3: TEdit;
    ListBox1: TListBox;
    Label4: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  plik:TextFile;
  linia_klient,linia_video:array[0..20] of string;
  id:integer;

implementation

{$R *.dfm}
{$IOCHECKS ON}
procedure TForm1.FormCreate(Sender: TObject);
var i:integer;
begin
Edit1.Text:='Witaj, Podaj ID klienta';
Label1.Caption:='ID';
AssignFile(plik,'klienci.txt');
Reset(plik);
i:=0;
While Not Eof(plik) do
  begin
    Readln(plik,linia_klient[i]);
    inc(i);
  end;

CloseFile(plik);
AssignFile(plik,'video.txt');
Reset(plik);
i:=0;
While Not Eof(plik) do
  begin
    Readln(plik,linia_video[i]);
    inc(i);
  end;

CloseFile(plik);
end;

procedure TForm1.Button1Click(Sender: TObject);
//var i: integer;
begin
id:=(strtoint(Edit1.Text)-1)*4;

AssignFile(plik,'\klienci\'+linia_klient[id]+'.txt');
try
Reset(plik);
except
  on EInOutError do Rewrite(plik);
  end;
edit2.Text:=linia_klient[id+1];
edit3.Text:=linia_klient[id+2];
//ListBox1.Clear;
//ListBox1.Items.Add();
end;

end.
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
Błażej
  • 3,617
  • 7
  • 35
  • 62

2 Answers2

9

The exception EInOutError will only be raised if I/O checking is enabled. To make sure it is enabled do the following:

  • In your project options, in "Delphi Compiler Options" check the checkbox I/O checking
  • Remove any {$IOCHECKS OFF} or {$I-} directives from your code as they disable I/O checking

This should give you a proper exception if the file doesn't exist.

Now if (for whatever reason) you cannot enable I/O checking:

With disabled I/O checking you won't get an EInOutError if something goes wrong. Instead you have to check the value of IOResult after every I/O operation. It's like in old Pascal times: If IOResult <> 0 then an error happened. This (slightly adapted) excerpt from the Delphi docs shows how to work with IOResult:

  AssignFile(F, FileName);
  {$I-}
  Reset(F);
  {$I+}
  if IOResult = 0 then
  begin
    MessageDlg('File size in bytes: ' + IntToStr(FileSize(F)),
      mtInformation, [mbOk], 0);
    CloseFile(F);
  end
  else
    MessageDlg('File access error', mtWarning, [mbOk], 0);

However, nowadays you should use TFileStream to access/create files and don't use the old style Pascal routines anymore. An example how this could look:

filename := '\klienci\'+linia_klient[id]+'.txt';
if not FileExists(filename) then
  // "Create a file with the given name. If a file with the given name exists, open the file in write mode."
  fs := TFileStream.Create(filename, fmCreate) else
  // "Open the file to modify the current contents rather than replace them."
  fs := TFileStream.Create(filename, fmOpenReadWrite);  
Heinrich Ulbricht
  • 10,064
  • 4
  • 54
  • 85
  • No. Seeing it as "exceptions don't work and I don't know why". – Heinrich Ulbricht Dec 12 '11 at 14:17
  • I edited to make it sound less like I would recommend toggling them off. – Heinrich Ulbricht Dec 12 '11 at 14:22
  • Ok But fmCreate will erase file content. – Błażej Dec 12 '11 at 14:35
  • @Dudi Use `fmOpenReadWrite` to open an existing file for reading and writing. You can first check the file existance with `FileExists('myfile.ext')` or try to open it with `fmOpenReadWrite`, catch the exception and then create it with `fmCreate`. (Added edit showing the first approach with explicit checking.) – Heinrich Ulbricht Dec 12 '11 at 14:37
  • Interesting: the German translation of the fmCreate documentation skips the fact that the content of the file will be deleted if it already exists while the English one explicitly states that. – Heinrich Ulbricht Dec 12 '11 at 14:42
  • Thanks, but how can I operate at this file with TFileStream? How should I add it to listbox as I do it befor with Text File. – Błażej Dec 12 '11 at 15:15
  • @David Agreed and trying. But I won't let go of the `IOResult` ;) Maybe somebody has to maintain legacy code or whatnot. – Heinrich Ulbricht Dec 12 '11 at 16:31
  • 1
    @David One might be offended by the occasional lecture in your answers. But a good lecture is OK for me and you got my +1 for superb technical writing. – Heinrich Ulbricht Dec 12 '11 at 16:49
6

I interpret your question that you would like EInOutError exceptions to be raised whenever a Pascal style I/O function fails. In order to do this you need to enable the I/O checking compiler option.

I/O checking: Enables or disables the automatic code generation that checks the result of a call to an I/O procedure. If an I/O procedure returns a nonzero I/O result when this switch is on, an EInOutError exception is raised (or the program is terminated if exception handling is not enabled). When this switch is off, you must check for I/O errors by calling IOResult.

I guess the code you are working with was written under the assumption that the I/O checking option was enabled, but that you are compiling with it not enabled. Here's a bit of code that demonstrates EInOutError being raised due to an I/O error.

program IOchecking;
{$APPTYPE CONSOLE}
{$IOCHECKS ON}
uses
  SysUtils;
var
  F: File;
begin
  AssignFile(F, 'path/to/file/that/does/not/exist');
  Reset(F);//raises EInOutError
end.

I strongly recommend that you enable I/O checking. This will allow you to handle errors using exceptions in a manner consistent with the rest of your code.

Not using I/O checking forces you to check the value of IOResult after every I/O function. This is very error prone (it's easy to forget to check) and results in untidy code.

If you are already running with I/O checking enabled then the most likely explanation for you not seeing an error is that in fact no error is occurring. Perhaps the file does in fact exist.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • 1
    Anyone know why this is downvoted. I must confess to having a hard time understanding the voting on this question. Did I misunderstand the question? I'd just like to know. – David Heffernan Dec 12 '11 at 16:21