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

发布于 12-21 03:39 字数 1940 浏览 2 评论 0原文

我正在使用旧式 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;

整个代码:

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.

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

迟到的我2024-12-28 03:39:06

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

  • 在项目选项中的“Delphi 编译器选项”中,选中复选框 I/O 检查
  • 删除任何 {$IOCHECKS OFF} 或 {$I-} 指令你的代码,因为它们禁用 I/O 检查

如果文件不存在,这应该会给你一个适当的异常。

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

通过禁用 I/O 检查,如果出现问题,您将不会收到 EInOutError 错误。相反,您必须在每次之后检查 IOResult 的值输入/输出操作。就像在旧的 Pascal 时代: If 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);

但是,现在您应该使用 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);  

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);  
违心°2024-12-28 03:39:06

我将您的问题解释为您希望在 Pascal 风格的 I/O 函数失败时引发 EInOutError 异常。为此,您需要启用I/O 检查编译器选项

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

我猜您正在使用的代码是在启用 I/O 检查选项的假设下编写的,但您在未启用该选项的情况下进行编译。下面的一段代码演示了由于 I/O 错误而引发的 EInOutError

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/O 检查。这将允许您以与代码的其余部分一致的方式使用异常来处理错误。

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

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文