为什么I/O错误无法引发异常?

Bła*_*żej 6 delphi pascal

我正在使用旧式Pascal I/O例程,并期望对失败的I/O函数的调用应该引发EInOutError.当我尝试这个时,我没有看到异常提出,我不知道为什么.

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;
Run Code Online (Sandbox Code Playgroud)

整个代码:

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.
Run Code Online (Sandbox Code Playgroud)

Hei*_*cht 8

EInOutError只有在启用 I/O检查时才会引发异常.要确保它已启用,请执行以下操作:

  • 在项目选项中,在"Delphi Compiler Options"中选中复选框I/O检查
  • 从代码中删除任何{$ IOCHECKS OFF}或{$ I-}指令,因为它们禁用了I/O检查

如果文件不存在,这应该给你一个适当的例外.

现在,如果(无论出于何种原因)您无法启用I/O检查:

使用禁用的 I/O检查,EInOutError如果出现问题,您将无法获得.相反,您必须在每次I/O操作后检查IOResult的值.这就像在旧帕斯卡时代:如果IOResult <> 0那时发生了错误.Delphi文档中的这个(略微改编)摘录展示了如何使用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);
Run Code Online (Sandbox Code Playgroud)

但是,现在您应该使用TFileStream访问/创建文件,而不再使用旧式Pascal例程.这看起来如何:

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);  
Run Code Online (Sandbox Code Playgroud)


Dav*_*nan 6

我解释您的问题,即EInOutError每当Pascal样式I/O函数失败时,您都希望引发异常.为此,您需要启用I/O检查编译器选项.

I/O检查:启用或禁用自动代码生成,以检查对I/O过程的调用结果.如果此开关打开时I/O过程返回非零I/O结果,则会引发EInOutError异常(或者如果未启用异常处理,程序将终止).当此开关关闭时,您必须通过调用IOResult来检查I/O错误.

我猜你正在使用的代码是在假设I/O检查选项已启用的情况下编写的,但是您正在编译它未启用它.这里有一些代码可以演示EInOutError由于I/O错误而引发的问题.

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.
Run Code Online (Sandbox Code Playgroud)

我强烈建议您启用I/O检查.这将允许您以与代码的其余部分一致的方式使用异常处理错误.

不使用I/O检查会强制您检查IOResult每个I/O功能之后的值.这非常容易出错(很容易忘记检查)并导致代码不整齐.

如果您已经在启用了I/O检查的情况下运行,那么最可能的解释是您没有看到错误,实际上没有发生错误.也许该文件确实存在.