在我的服务器上有一些文件与修改日期31 / DEC / 1979(不要问我为什么).所以FileExists返回false.
Sysutils.FileExists看起来像这样:
function FileAge(const FileName: string): Integer; var Handle: THandle; FindData: TWin32FindData; LocalFileTime: TFileTime; begin Handle := FindFirstFile(PChar(FileName),FindData); if Handle <> INVALID_HANDLE_VALUE then begin Windows.FindClose(Handle); if (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = 0 then begin FileTimeToLocalFileTime(FindData.ftLastWriteTime,LocalFileTime); if FileTimeToDosDateTime(LocalFileTime,LongRec(Result).Hi,LongRec(Result).Lo) then Exit; end; end; Result := -1; end; function FileExists(const FileName: string): Boolean; begin Result := FileAge(FileName) <> -1; end;
我的问题是,为什么这个功能首先依赖于FileAge?
以下行不足够吗?
if (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = 0 then // Yes the file exists!
function MyFileExists(const Name: string): Boolean; var R: DWORD; begin R := GetFileAttributes(PChar(Name)); Result := (R <> DWORD(-1)) and ((R and FILE_ATTRIBUTE_DIRECTORY) = 0); end;
解决方法
Delphi的现代版本与您的代码完全相同,实现了FileExists.该实现对符号链接具有额外的处理,但与其版本基本相同.
现代德尔福实现有一个有趣的细微差别.如果对GetFileAttributes的调用返回INVALID_FILE_ATTRIBUTES,则代码不会立即保释.而是这样做:
LastError := GetLastError; Result := (LastError <> ERROR_FILE_NOT_FOUND) and (LastError <> ERROR_PATH_NOT_FOUND) and (LastError <> ERROR_INVALID_NAME) and ExistsLockedOrShared(Filename);
ExistsLockedOrShared的实现使用FindFirstFile和对dwFileAttributes的FILE_ATTRIBUTE_DIRECTORY的检查.这表示GetFileAttributes在文件存在但被锁定时可能会失败.但是FindFirstFile可以在这种情况下成功.这是合理的,因为FindFirstFile使用文件元数据而不是文件中存储的数据.
很难说为什么代码是旧版本的方式.我觉得它很弱.我个人使用代码钩替换FileExists更好的版本.例如:Patch routine call in delphi
一如以往,有一篇关于这个问题的Raymond Chen文章:Superstition: Why is GetFileAttributes the way old-timers test file existence?