创建FileStream时如何处理异常

发布于 2024-10-01 10:37:56 字数 1183 浏览 6 评论 0原文

我有一个这样的函数,我想重构

   function Myfunction(sUrl, sFile: String) : Boolean;
    var
      GetData : TFileStream;
    begin
      Result := False;
      //if the line below fails, I get an unhandled exception
      GetData := TFileStream.Create(sFile, fmOpenWrite or fmCreate);
      try        
        try
          IdHTTP.Get(sUrl, GetData);
          Result := (IdHTTP.ResponseCode = 200);
        except
          on E: Exception do begin
            MessageBox(0, PChar(E.message), 'Niðurhala skrá', MB_ICONERROR or MB_OK);
          end;
        end;
      finally
        GetData.Free;
      end;
    end;

    Procedure SomeOtherCode;
     Begin
        //How can I best defend against the unhandled exception above
        //unless the call to the function is packed in a try .. except block
        //the code jumps skips the if statement an goes to next 
        //exception block on the stack
        if MyFunction('http://domain.com/file.html', 'c:\folder\file.html') then
            ShowMessage('Got the file')
         else
            ShowMessage('Error !');
        End
     end;

问题:

请参阅上面过程 SomeOtherCode 中的注释。

此致

I have a function like this, that I would like to refactor

   function Myfunction(sUrl, sFile: String) : Boolean;
    var
      GetData : TFileStream;
    begin
      Result := False;
      //if the line below fails, I get an unhandled exception
      GetData := TFileStream.Create(sFile, fmOpenWrite or fmCreate);
      try        
        try
          IdHTTP.Get(sUrl, GetData);
          Result := (IdHTTP.ResponseCode = 200);
        except
          on E: Exception do begin
            MessageBox(0, PChar(E.message), 'Niðurhala skrá', MB_ICONERROR or MB_OK);
          end;
        end;
      finally
        GetData.Free;
      end;
    end;

    Procedure SomeOtherCode;
     Begin
        //How can I best defend against the unhandled exception above
        //unless the call to the function is packed in a try .. except block
        //the code jumps skips the if statement an goes to next 
        //exception block on the stack
        if MyFunction('http://domain.com/file.html', 'c:\folder\file.html') then
            ShowMessage('Got the file')
         else
            ShowMessage('Error !');
        End
     end;

Question:

Please refer to the comment within the procedure SomeOtherCode above.

Best Regards

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

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

发布评论

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

评论(6

不语却知心 2024-10-08 10:37:56

只需将要捕获异常的代码包装在 try..except 块中即可:

function MyFunction(...): Boolean;
var
  Stream: TFileStream;
begin
  Result := False;
  try
    Stream := TFileStream.Create(...);
    try
      // more code
      Result := ...
    finally
      Stream.Free;
    end;
  except
    // handle exception
  end
end;

Just wrap the code where you want to trap exceptions in a try..except block:

function MyFunction(...): Boolean;
var
  Stream: TFileStream;
begin
  Result := False;
  try
    Stream := TFileStream.Create(...);
    try
      // more code
      Result := ...
    finally
      Stream.Free;
    end;
  except
    // handle exception
  end
end;
浮生面具三千个 2024-10-08 10:37:56

关于异常处理的全部要点有两个:

  • finally 用于资源清理;您在业务逻辑中经常看到这种情况
  • except 用于对特定异常做出反应(并通过函数结果和中间变量摆脱状态逻辑);您在业务逻辑中几乎看不到它

在您的情况下:

Myfunction不应返回布尔值,不应包含except块,也不应执行MessageBox但只是让异常传播。
SomeOtherCode 应包含 except 块并告诉用户出了什么问题。

示例:

procedure Myfunction(sUrl, sFile: String);
var
  GetData: TFileStream;
begin
  Result := False;
  //if the line below fails, I get an unhandled exception
  GetData := TFileStream.Create(sFile, fmOpenWrite or fmCreate);
  try        
    IdHTTP.Get(sUrl, GetData);
    if (IdHTTP.ResponseCode <> 200) <> then
      raise Exception.CreateFmt('Download of %s failed, return code %d', [sURl, IdHTTP.ResponseCode]);
  finally
    GetData.Free;
  end;
end;

procedure SomeOtherCode:
begin
  try
    MyFunction('http://domain.com/file.html', 'c:\folder\file.html');
  except
    on E: Exception do begin
      MessageBox(0, PChar(E.message), 'Niðurhala skrá', MB_ICONERROR or MB_OK);
    end;
  end;
end;

现在代码更加简洁:

  • 业务逻辑中不再有 UI,在
  • 处理 except 的地方,
  • 所有失败都会得到同等处理(无法创建文件下载失败

祝你好运。

——杰罗恩

The whole point about exception handling is two-fold:

  • finally is for resource cleanup; you see this often in business logic
  • except is for reacting on specific exception (and getting rid of state logic through function results and intermediate variables); you hardly see it in business logic

In your case:

Myfunction should not return a Boolean, not contain an except block, and not perform a MessageBox but just let the exceptions propagate.
SomeOtherCode should contain the except block and tell the user what went wrong.

Example:

procedure Myfunction(sUrl, sFile: String);
var
  GetData: TFileStream;
begin
  Result := False;
  //if the line below fails, I get an unhandled exception
  GetData := TFileStream.Create(sFile, fmOpenWrite or fmCreate);
  try        
    IdHTTP.Get(sUrl, GetData);
    if (IdHTTP.ResponseCode <> 200) <> then
      raise Exception.CreateFmt('Download of %s failed, return code %d', [sURl, IdHTTP.ResponseCode]);
  finally
    GetData.Free;
  end;
end;

procedure SomeOtherCode:
begin
  try
    MyFunction('http://domain.com/file.html', 'c:\folder\file.html');
  except
    on E: Exception do begin
      MessageBox(0, PChar(E.message), 'Niðurhala skrá', MB_ICONERROR or MB_OK);
    end;
  end;
end;

Now the code is much cleaner:

  • no more UI in your business logic
  • one place where your except is being handled
  • all failures are handled equally (cannot create file, download failure)

Good luck with this.

--jeroen

李不 2024-10-08 10:37:56

如果您希望函数向用户显示消息并在任何失败时返回 false,请按如下方式编码:

function Myfunction(sUrl, sFile: String) : Boolean;
var
  GetData : TFileStream;
begin
  Result := False;
  try
    //if the line below fails, I get an unhandled exception
    GetData := TFileStream.Create(sFile, fmOpenWrite or fmCreate);
    try        
      try
        IdHTTP.Get(sUrl, GetData);
        Result := (IdHTTP.ResponseCode = 200);
      except
        on E: Exception do begin
          MessageBox(0, PChar(E.message), 'Niðurhala skrá', MB_ICONERROR or MB_OK);
        end;
      end;
    finally
      GetData.Free;
    end;
  except
    // you can handle specific exceptions (like file creation errors) or any exception here
  end;
end;

警告
恕我直言,这种设计混合了业务逻辑(例如从互联网获取资源/文件并将其保存到文件中)和用户界面逻辑(例如在出现错误时向用户显示消息)。

一般来说,这是将业务与 UI 逻辑分离的更好方法,因为您的代码是可重用的。

例如,您可能想要重构如下:

function DownloadToAFile(const sUrl, sFile: string): boolean;
var
  GetData : TFileStream;
begin
  GetData := TFileStream.Create(sFile, fmOpenWrite or fmCreate);
  try        
    IdHTTP.Get(sUrl, GetData);
    Result := (IdHTTP.ResponseCode = 200);
  finally
    GetData.Free;
  end;
end;

function UIDownloadToAFile(const sUrl, sFile: string): boolean;
begin
  try
    Result := DownloadToAFile(sURL, sFile);
  except
    on E: EIDException do //IndyError
      MessageBox(0, PChar(E.message), 'Internet Error', MB_ICONERROR or MB_OK);
    on E: EFileCreateError do //just can't remember the extact class name for this error
      MessageBox(0, PChar(E.message), 'File create Error', MB_ICONERROR or MB_OK);
  end;
end;

procedure SomeOtherCode:
begin
  if UIDownloadToAFile('http://domain.com/file.html', 'c:\folder\file.html') then
    ShowMessage('Got the file')
   else
     ShowMessage('Error !');
end;

明天,如果您正在编写服务或 DataSnap 模块,您可以自由地使用 DownloadToAFile 或者编写一个新的 ServiceDownloadToAFile ,然后将错误写入日志或 Windows 事件,或者发送电子邮件通知 HostAdmin。

If you want your function to show messages to the user and return false on any failure, code it as follows:

function Myfunction(sUrl, sFile: String) : Boolean;
var
  GetData : TFileStream;
begin
  Result := False;
  try
    //if the line below fails, I get an unhandled exception
    GetData := TFileStream.Create(sFile, fmOpenWrite or fmCreate);
    try        
      try
        IdHTTP.Get(sUrl, GetData);
        Result := (IdHTTP.ResponseCode = 200);
      except
        on E: Exception do begin
          MessageBox(0, PChar(E.message), 'Niðurhala skrá', MB_ICONERROR or MB_OK);
        end;
      end;
    finally
      GetData.Free;
    end;
  except
    // you can handle specific exceptions (like file creation errors) or any exception here
  end;
end;

Warning
IMHO this design is mixing business logic (such as get a resource/file from the Internet and save it to a file) and user interface logic (such as showing messages to the user in case of errors).

In general, is a better approach to separate business from UI logic, because your code is reusable.

For example you might want to re-factor as this:

function DownloadToAFile(const sUrl, sFile: string): boolean;
var
  GetData : TFileStream;
begin
  GetData := TFileStream.Create(sFile, fmOpenWrite or fmCreate);
  try        
    IdHTTP.Get(sUrl, GetData);
    Result := (IdHTTP.ResponseCode = 200);
  finally
    GetData.Free;
  end;
end;

function UIDownloadToAFile(const sUrl, sFile: string): boolean;
begin
  try
    Result := DownloadToAFile(sURL, sFile);
  except
    on E: EIDException do //IndyError
      MessageBox(0, PChar(E.message), 'Internet Error', MB_ICONERROR or MB_OK);
    on E: EFileCreateError do //just can't remember the extact class name for this error
      MessageBox(0, PChar(E.message), 'File create Error', MB_ICONERROR or MB_OK);
  end;
end;

procedure SomeOtherCode:
begin
  if UIDownloadToAFile('http://domain.com/file.html', 'c:\folder\file.html') then
    ShowMessage('Got the file')
   else
     ShowMessage('Error !');
end;

Tomorrow, if you're writing a service, or a DataSnap module, you're free to use the DownloadToAFile or maybe to write a new ServiceDownloadToAFile wich in turns writes errors to a log or windows events, or maybe send a email notifying the HostAdmin about it.

救星 2024-10-08 10:37:56

一种非常流行的解决方案是完全避免“成功”或“失败”返回值。不使用函数,而使用过程并使用异常处理失败:

procedure Download(sUrl, sFile: String);

然后

try
  Download ('http://domain.com/file.html', 'c:\folder\file.html');
  ShowMessage('Got the file')
except
  on E:Exxx do 
  begin
    // handle exception
    ShowMessage('Error !');
  end
end;

这也具有任何人都无法调用该函数并默默地忽略返回值的效果。

One solution which is quite popular is to avoid 'success' or 'failure' return values completely. Instead of a function, use a procedure and handle failures using exceptions instead:

procedure Download(sUrl, sFile: String);

and then

try
  Download ('http://domain.com/file.html', 'c:\folder\file.html');
  ShowMessage('Got the file')
except
  on E:Exxx do 
  begin
    // handle exception
    ShowMessage('Error !');
  end
end;

This has also the effect that nobody can invoke the function and silently ignore the return value.

雪若未夕 2024-10-08 10:37:56

由于某种原因,大多数人滥用 except-finally 组合。正确的顺序是

try 
  // allocate resource here
  try 
  finally
    // free resource here
  end;
except
  // handle exception here
end;

这可以让您捕获构造函数和析构函数中的异常。

For some reason most people misuse except-finally combination. Correct sequence is

try 
  // allocate resource here
  try 
  finally
    // free resource here
  end;
except
  // handle exception here
end;

This lets you catch exceptions in constructor and destructor.

淡淡绿茶香 2024-10-08 10:37:56

您应该只使用一次 try 并获取所有函数代码。

You should use only one try and get in this your all function code.

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