7

关于获取文件的大小,我有这两个功能:

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

嗯,明显的区别就是GetFileSize2打开文件,使用CreateFileAPI​​获取文件句柄。相反,GetFileSize1不会因为它从文件元数据中读取大小。

所以我希望GetFileSize1表现更好。虽然,对于许多应用程序而言,性能差异并不重要。更重要的是,在将成功GetFileSize2的情况下,可能会由于共享冲突而失败。GetFileSize1所以你真的不应该使用GetFileSize2.

另请注意,您提供的两个函数在发生错误时的行为不同: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;

有些感觉这比 call 更自然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-Call),而 GetFileSize2 直接接触文件(获取 FileHandle,遍历到最后计算大小)。

因此 GetFileSize1 消耗的性能/资源少于 GetFileSize2

更新

我忘了提一下,如果文件已经在使用中,你可能不允许使用 TFileStream 访问,但元信息将可用。

更新(只是大卫建议的另一个变体)

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 回答