在使用DeleteFile()之前,检查FileExists()是否必须?

3

我很久以前在某个地方读到了一个Delphi的最佳实践。

这是不推荐的写法:

if FileExists(MyFile) then begin
        if not DeleteFile(MyFile) then
                ShowMessage('Unable to delete file');
end;

请写下以下内容:

if not DeleteFile(MyFile) then
        ShowMessage('Unable to delete file');

第二个的优缺点是什么?


1
在第一种方法中,如果文件不存在,用户根本不会收到任何消息,因此他不知道它是否被删除。在第二种方法中,如果删除失败,用户将始终得到通知。因此,哪种方法更好取决于您希望用户看到什么。 - GuidoG
这里有两个使用案例:1. 你预期文件可能不存在,这不是一个错误;2. 文件必须存在,如果不存在,我们就会得到一个错误。 - zed
在第一种方法中,在进行FileExists检查和DeleteFile调用之间,文件有可能会被另一个进程删除,从而使FileExists检查变得多余,因为您不能依靠它。 - HeartWare
6
更好的方法是直接调用DeleteFile函数,如果失败了,就使用GetLastError函数来确定它失败的原因。如果是ERR_FILE_NOT_FOUND错误代码,那么你就知道是因为文件不存在。如果是ERR_ACCESS_DENIED错误代码,那么你就知道文件存在,但是你无法删除它(它可能正在另一个进程中被打开或标记为只读)。这样,你就可以处理所有情况,而不会基于失效的FileExists调用结果得出错误结论。 - HeartWare
@Heartware 我相信也有可能是 ERROR_PATH_NOT_FOUND。 - David Heffernan
@DavidHeffernan: 确实如此...还可能有其他几个错误...例如,如果该文件位于已被移除的USB驱动器上,则会出现“驱动器未就绪”。 - HeartWare
2个回答

8
为了更清晰地阐述,我将您问题中的代码理解为想要删除文件,仅在文件存在且无法被删除时报告错误。
在尝试删除文件之前检查文件是否存在不是最佳实践。事实上,这样做是一种经典的反模式。
正确的模式是直接尝试删除文件。如果失败,则检查失败原因。这将告诉您文件是否存在,或者删除失败是由于其他原因。在Windows上,这意味着使用名为DeleteFile的Win32 API函数,并检查其成功或失败的返回值。在失败的情况下,调用GetLastError以获取失败的原因。
以跨平台方式执行此操作并不完全简单,我认为RTL没有提供这种功能。
另外值得指出的是,您的两个代码块并不可互换。它们具有不同的行为。第一个代码块将文件不存在视为成功。第二个代码块将其视为错误。如果您希望通过仅使用单个函数调用来重现第一个行为,则需要根据错误代码进行区分,如上所述。

SysUtils.pas 中的 DeleteFile() 不是跨平台的吗? - Arnaud Bouchez
@Arnaud 是的,但错误原因的区分不是该API的一部分,对吧? - David Heffernan
它返回一个布尔值表示成功或失败。OP并不关心低级错误的原因,只关心是否成功。 - Arnaud Bouchez
1
@Arnaud 不完全是。检查文件是否存在的代码将其不存在视为成功。 - David Heffernan

5

调用 FileExists() 是没有意义的。

这个文件可能存在,但是无法被删除 - 例如,如果它是只读的,或者被另一个进程锁定。与调用 DeleteFile() 相比,它不会更快。

因此,第二个版本更可取:

if not DeleteFile(MyFile) then
    ShowMessage('Unable to delete file');

注意:SysUtils.pas 中的 DeleteFile() 是跨平台的,返回一个布尔值表示成功 - 因为注释和一些答案仅涉及来自 Windows.pas 的原始 API 调用。


1
非常值得指出的是,这两个代码块不能互换。第二个代码块,在本答案中重复,将文件未找到视为错误。 - David Heffernan
这完全取决于你想要什么样的行为。但是,当你期望删除一个文件却无法完成时,就没有必要使用FileExists。如果你希望向用户指出失败的原因,并且想要一个跨平台解决方案,则可以使用FileExists来检测缺失的文件与无法删除的现有文件之间的差异... - R. Hoek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接