FileExists和修改日期的问题

时间:2012-12-19 18:56:32

标签: delphi delphi-7

在我的服务器上有一些文件的修改日期为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;

3 个答案:

答案 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;