在 delphi XE 中,当我使用以下输入调用 SysUtils DirectoryExists 函数时
'Y:\blabla\'
其中 Y 是网络映射单元,它正确返回 false,因为 blabla 不存在。
但是当我使用以下输入调用时
'Y:\blabla\Y:\bla'
它返回真。
文档很差,我在互联网上的任何地方都没有找到有同样问题的人
也许这里有人已经遇到过这个问题,或者知道发生了什么?
这似乎是DirectoryExists函数实现中的一个错误。
这是这个函数的相关代码
function DirectoryExists(const Directory: string; FollowLink: Boolean = True): Boolean;
{$IFDEF MSWINDOWS}
var
Code: Cardinal;
Handle: THandle;
LastError: Cardinal;
begin
Result := False;
Code := GetFileAttributes(PChar(Directory));
if Code <> INVALID_FILE_ATTRIBUTES then
begin
...
//more code
...
end
else
begin
LastError := GetLastError;
Result := (LastError <> ERROR_FILE_NOT_FOUND) and
(LastError <> ERROR_PATH_NOT_FOUND) and
(LastError <> ERROR_INVALID_NAME) and
(LastError <> ERROR_BAD_NETPATH);
end;
end;
{$ENDIF MSWINDOWS}
如您所见,如果GetFileAttributes
函数调用失败,则将该GetLastError
方法的结果与一组可能的值进行比较。但在您的情况下,传递无效路径将返回ERROR_BAD_PATHNAME
(161) 代码,因此该函数返回 True。
该错误在 XE8 中仍然存在(可能也在其他版本中)。正如上面 RRUZ 指出的,它存在于DirectoryExists()和TDirectory.Exists()的SysUtils 实现中。
问题在于一长串“检查”假定它们是在文件夹“存在”的上下文中可能返回 INVALID_FILE_ATTRIBUTES的唯一有效原因。但是我们调用这些例程的原因几乎总是这样我们可以检查我们是否可以实际使用我们询问的文件夹。拥有 INVALID_FILE_ATTRIBUTES 几乎总是意味着我们不能。无论哪种方式,目前正在进行的测试都不会产生合理的结果。仅此事实就使其成为完全多余的练习,因为它允许某些其他故障代码通过网络并在不应该的情况下将最终结果设置为 TRUE。虽然我只能想象这种疯狂本来有一些方法,但按照“哦,它存在但可能无效”的思路,它违背了未来可能会带来更多由许多人生成的代码的内在真理未知的文件系统和/或硬件:所以底线是对于 99.9% 的使用,获取INVALID_FILE_ATTRIBUTES应该意味着文件夹不可用,因此一旦已经确定就允许返回 TRUE 是不合逻辑的。
不幸的是,我们不知道是否存在依赖当前行为来识别“存在问题的现有路径”的代码 - 在这种情况下,对当前存在的例程的调用必须首先进行路径语法验证检查:否则它会说用错误语法描述的路径“存在”,这是胡说八道!之后您不能重做GetLastError,因为错误已被清除。
因此,唯一的解决方法是使用可以预先消除问题的代码来包装任何Sysutils.DirectoryExists和(不幸的是)TDirectory.Exists调用。例如:
DirectoryUsable(const Directory: string; FollowLink: Boolean = True): Boolean;
begin
Result := GetFileAttributes(PChar(Directory)) <> INVALID_FILE_ATTRIBUTES;
if Result then Result := DirectoryExists( Directory, FollowLink );
end;
要么这样,要么你对你知道的所有“坏”案例和 Embarcadero 错过的所有“坏”案例进行单独的预先验证——即和他们一样玩同样的失败游戏。可怕,但你去。
您还可以自己修改 SysUtils 库,以添加丢失的案例,您必须在每个 Delphi 版本和遇到的每个新案例中重做。如果 Embarcadero 最终“咬紧牙关”并为这个问题找到更好的解决方案,那可能会更好。也许通过使用另一个默认的标志参数,即“拒绝所有无效目录”。我会进一步建议这默认为 TRUE。