7

ファイルのサイズの取得については、次の 2 つの関数があります。

function GetFileSize1(const FileName: TFileName): Int64;
var
 iTmp: Int64;
 SearchRec: TSearchRec;
begin
  iTmp := -1;
  if FindFirst(FileName, faAnyFile, SearchRec) = 0 then
  begin
    iTmp := SearchRec.Size;
    System.SysUtils.FindClose(SearchRec);
  end;
  Result := iTmp;
end;

と:

function GetFileSize2(const FileName: TFileName): Int64;
var
 FileStream: TFileStream;
begin
  FileStream := TFileStream.Create(FileName, fmOpenRead);
  try
    Result := FileStream.Size; 
  finally  
    FileStream.Free;
  end; 
end;

実際には、それの違いは何ですか?もちろん、どちらも同じ結果を返しますが、どちらがより手頃で、より速く、より安全でしょうか? またはより良い、好ましい使用は何ですか?ファーストかセカンドか?どうもありがとう。

4

2 に答える 2

8

明らかな違いは、 API をGetFileSize2使用してファイル ハンドルを取得してファイルを開くことです。CreateFile対照的にGetFileSize1、ファイルのメタデータからサイズを読み取るため、そうではありません。

GetFileSize1ですから、より良いパフォーマンスを期待したいと思います。ただし、多くのアプリケーションでは、パフォーマンスの違いは問題になりません。さらに重要なことに、成功するGetFileSize2状況でも共有違反が原因で失敗する可能性があります。GetFileSize1したがって、実際には使用しないでくださいGetFileSize2

また、提示した 2 つの関数は、エラーが発生した場合の動作が異なることに注意してください。GetFileSize1-1 を返しGetFileSize2、例外を発生させます。

個人的に私はこのバージョンを好みます:

function GetFileSize3(const FileName: string): Int64;
var
  fad: TWin32FileAttributeData;
begin
  if not GetFileAttributesEx(PChar(FileName), GetFileExInfoStandard, @fad) then
    RaiseLastOSError;
  Int64Rec(Result).Lo := fad.nFileSizeLow;
  Int64Rec(Result).Hi := fad.nFileSizeHigh;
end;

または、エラーの場合に -1 を返したい場合は、次のように記述します。

function GetFileSize3(const FileName: string): Int64;
var
  fad: TWin32FileAttributeData;
begin
  if not GetFileAttributesEx(PChar(FileName), GetFileExInfoStandard, @fad) then
    exit(-1);
  Int64Rec(Result).Lo := fad.nFileSizeLow;
  Int64Rec(Result).Hi := fad.nFileSizeHigh;
end;

を呼び出すよりも自然に感じる方法もありますFindFirstFileが、それはおそらく個人的な好みです。FindFirstFileアプローチに間違いはありません。そのiTmp変数は必要ありませんが。次のように、より明確に記述できます。

function GetFileSize1(const FileName: TFileName): Int64;
var
 SearchRec: TSearchRec;
begin
  if FindFirst(FileName, faAnyFile, SearchRec) = 0 then
  begin
    Result := SearchRec.Size;
    System.SysUtils.FindClose(SearchRec);
  end
  else
    Result := -1;
end;

更新: @CodeInChaos は、ファイル ハンドルを開かないアプローチについて適切に指摘しています。これらのアプローチは、ハード リンクされたファイルに対して不正確な結果をもたらす可能性があります。

于 2012-11-17T13:43:33.560 に答える
1

違いは、GetFileSize1 はファイルのメタ情報を読み取り (Windows API 呼び出し)、GetFileSize2 はファイルに直接アクセスする (FileHandle を取得し、最後までウォークスルーしてサイズを計算する) ことです。

したがって、GetFileSize1 は GetFileSize2 よりも少ないパフォーマンス/リソースを消費します

アップデート

言い忘れましたが、ファイルが既に使用されている場合、TFileStream でのアクセスは許可されていない可能性がありますが、メタ情報は利用できます。

更新 (Davids の提案の別のバリアント)

function GetFileSize1(const FileName: TFileName): Int64;
var
 SearchRec: TSearchRec;
begin
  if FindFirst( FileName, faAnyFile, SearchRec ) = 0 then
    try
      Exit( SearchRec.Size );
    finally
      System.SysUtils.FindClose(SearchRec);
    end;
  Result := -1;
end;
于 2012-11-17T13:43:30.780 に答える