12

私のサーバーには、更新日が 31/DEC/1979 のファイルがいくつかあります (理由は聞かないでください)。したがって、FileExistsfalse を返します。

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;
4

3 に答える 3

11

Delphi の最新バージョンはFileExists、コードとほぼ同じ方法で実装されています。実装にはシンボリックリンクの追加処理がありますが、それ以外は基本的にあなたのバージョンと同じです。

最新の Delphi 実装には、興味深いニュアンスが 1 つあります。への呼び出しが を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);

そして、ExistsLockedOrSharedusesの実装とonFindFirstFileのチェック 。これは、ファイルが存在するがロックされている場合に失敗する可能性があることを示します。しかし、それはそのようなシナリオで成功する可能性があります。ファイル自体に格納されているデータではなく、ファイルのメタデータを使用するため、これは合理的です。FILE_ATTRIBUTE_DIRECTORYdwFileAttributesGetFileAttributesFindFirstFileFindFirstFile

コードが古いバージョンのようになっている理由を言うのは難しいです。弱いと思います。個人的にはFileExists、コード フックを使用して、より良いバージョンに置き換えます。例: Delphi でのパッチ ルーチン呼び出し

いつものように、レイモンド・チェンの記事があります:迷信: なぜ古いタイマーがファイルの存在をテストする方法なのですか?

于 2012-12-19T19:14:43.827 に答える
4

の「モダン」実装から判断するとFileExists(これは使用せずFileAge、最適化されており、リンクされたファイルが存在するかどうかを確認するためにシンボリックリンクをたどることができます):

  • 最初のバリアント((FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = 0)はOKです。
  • GetFileAttributesファイルがロックまたは共有されている場合、2番目のバリアント( )は失敗する可能性があります。
于 2012-12-19T19:25:35.310 に答える
1

For old Delphi versiosn you can download Jedi Code Library. It has the following implementation (aside of many other useful classes and functions):

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;
于 2012-12-20T07:42:00.543 に答える