delphi 目录存在网络映射单元的函数奇怪行为

问题描述 投票:0回答:3

在delphi XE中,当我使用以下输入调用SysUtils DirectoryExists函数时

'Y: 唇彩\'

其中 Y 是网络映射单元,它正确返回 false,因为 blabla 不存在。

但是当我使用以下输入拨打电话时

'Y: 拉布拉\Y: 拉'

它返回true。

文档很差,我在互联网上没有找到有同样问题的人

也许这里有人已经遇到过这个问题,或者知道发生了什么?

delphi function directory delphi-xe exists
3个回答
6
投票

这似乎是 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。


0
投票

该错误在 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

0
投票

所以现在我使用的功能不是很好,但是可以工作:

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)但它有效

© www.soinside.com 2019 - 2024. All rights reserved.