在我的服务器上有一些文件的修改日期为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;
答案 0 :(得分:11)
现代版本的Delphi实现FileExists
的方式与代码的实现方式大致相同。该实现对符号链接有额外的处理,但在其他方面基本上与您的版本相同。
现代Delphi实现中有一个有趣的细微差别。如果对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
并检查FILE_ATTRIBUTE_DIRECTORY
上的dwFileAttributes
。这表示文件存在时GetFileAttributes
可能会失败,但会被锁定。但FindFirstFile
可以在这种情况下取得成功。这是合理的,因为FindFirstFile
使用文件元数据而不是文件本身存储的数据。
很难说为什么代码就像旧版本一样。我觉得它很弱。我个人会用更好的版本替换FileExists
,使用代码钩子。例如:Patch routine call in delphi
与往常一样,有一篇关于此主题的Raymond Chen文章:Superstition: Why is GetFileAttributes the way old-timers test file existence?
答案 1 :(得分:4)
根据FileExists
的'现代'实现来判断(它不使用FileAge
并且还进行了优化,并且可以按照符号链接来检查链接文件是否存在):
(FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = 0
)没问题; GetFileAttributes
)可能会失败。答案 2 :(得分:1)
对于旧的Delphi versiosn,您可以下载Jedi代码库。它具有以下实现(除了许多其他有用的类和函数):
function FileExists(const FileName: string): Boolean;
{$IFDEF MSWINDOWS}
var
Attr: Cardinal;
{$ENDIF MSWINDOWS}
begin
if FileName <> '' then
begin
{$IFDEF MSWINDOWS}
// FileGetSize is very slow, GetFileAttributes is much faster
Attr := GetFileAttributes(Pointer(Filename));
Result := (Attr <> $FFFFFFFF) and (Attr and FILE_ATTRIBUTE_DIRECTORY = 0);
{$ELSE ~MSWINDOWS}
// Attempt to access the file, doesn't matter how, using FileGetSize is as good as anything else.
Result := FileGetSize(FileName) <> -1;
{$ENDIF ~MSWINDOWS}
end
else
Result := False;
end;