在delphi XE中,当我使用以下输入调用SysUtils DirectoryExists函数时
'Y: 唇彩\'
其中 Y 是网络映射单元,它正确返回 false,因为 blabla 不存在。
但是当我使用以下输入拨打电话时
'Y: 拉布拉\Y: 拉'
它返回true。
文档很差,我在互联网上没有找到有同样问题的人
也许这里有人已经遇到过这个问题,或者知道发生了什么?
这似乎是 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 上面指出的,它位于 BOTH DirectoryExists() 和 TDirectory.Exists().
的 SysUtils 实现中。问题在于一长串“检查”,假设它们是在文件夹“存在”的上下文中可能返回 INVALID_FILE_ATTRIBUTES 的“唯一有效原因”。但我们调用这些例程的原因是“几乎总是”,因此我们可以检查我们是否实际上可以“使用”我们正在询问的文件夹。 INVALID_FILE_ATTRIBUTES 几乎总是意味着我们不能。不管怎样,目前正在进行的测试不会产生合理的结果。仅这一事实就使其成为完全多余的练习,因为它允许某些其他故障代码溜过网络,并将最终结果设置为 TRUE(而本不该设置为 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。
我对驱动器的映射路径也有同样的问题(
Y:
)。 完整路径也有同样的问题
\\IP\dir\dir
所以现在我使用的功能不是很好,但是可以工作:
function FolderExists(const BasePath: WideString): boolean;
const
FIND_FIRST_EX_LARGE_FETCH = $00000002;
FIND_FIRST_EX_ON_DISK_ENTRIES_ONLY = $00000004;
var
FindExHandle : THandle;
Win32FindData : TWin32FindDataW;
FindExInfoLevels: TFindexInfoLevels;
FindExSearchOps : TFindexSearchOps;
AdditionalFlags : DWORD;
i, ii : Integer;
folderTime: TDateTime;
begin
result := false;
FindExInfoLevels := _FINDEX_INFO_LEVELS.FindExInfoBasic;
FindExSearchOps := _FINDEX_SEARCH_OPS.FindExSearchLimitToDirectories;
AdditionalFlags := FIND_FIRST_EX_LARGE_FETCH or FIND_FIRST_EX_ON_DISK_ENTRIES_ONLY;
FindExHandle := Winapi.Windows.FindFirstFileExW(PWideChar(IncludeTrailingBackslash(TDirectory.GetParent(ExcludeTrailingPathDelimiter(BasePath))) + '*.*' ), FindExInfoLevels, @Win32FindData, FindExSearchOps, nil ,AdditionalFlags);
if (FindExHandle <> INVALID_HANDLE_VALUE) then
repeat
if ((Win32FindData.cFileName = ExtractFileName(ExcludeTrailingPathDelimiter(BasePath))) and (0 <> (Win32FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY))) then begin
result := true;
break;
end;
until not Winapi.Windows.FindNextFileW(FindExHandle, Win32FindData);
Winapi.Windows.FindClose(FindExHandle);
end;
函数可以很好地处理像
\\IP\dir\dir
这样的完整路径
是的,函数使用的不是最优算法:)(乐观:ON)但它有效