2004. március 18., csütörtök

How to determine file and tree sizes larger 2 GB


Problem/Question/Abstract:

How to determine file and tree sizes larger 2 GB

Answer:

Solve 1:

You will need to use the FindFirstFile, FindNextFile and FindClose functions, e.g.:

function GetFileSize(const FileName: string): Int64;
var
  F: TWin32FindData;
  H: THandle;
begin
  H := FindFirstFile(PChar(FileName), F);
  if H = INVALID_HANDLE_VALUE then
    RaiseLastWin32Error;
  try
    Result := F.nFileSizeHigh shl 32 + F.nFileSizeLow;
  finally
    Windows.FindClose(H);
  end;
end;

function GetTreeSize(FileName: string): Int64;

  procedure TreeSize(const FileName: string);
  var
    F: TWin32FindData;
    H: THandle;
  begin
    H := FindFirstFile(PChar(FileName), F);
    if H = INVALID_HANDLE_VALUE then
      RaiseLastWin32Error;
    try
      repeat
        if ((F.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) > 0) and (F.cFileName[0]
          <> '.') then
          TreeSize(ExtractFilePath(FileName) + F.cFileName + '\*.*')
        else
          Result := Result + F.nFileSizeHigh shl 32 + F.nFileSizeLow;
      until not FindNextFile(H, F);
    finally
      Windows.FindClose(H);
    end;
  end;

begin
  Result := 0;
  TreeSize(IncludeTrailingBackslash(ExtractFilePath(FileName)) + '*.*');
end;

I would add one little detail to your function. By calculating the filesize, you should cast the values to Int64. In the helpfile you can read, that this is necessary, because the operation would normally return an integer. In this case, (F.nFileSizeHigh shl 32) would return an Integer and not an Int64.

Result := Int64(F.nFileSizeHigh) shl 32 + Int64(F.nFileSizeLow);

I think, casting "nFileSizeLow" is not necessary, but better to make it safe.


Solve 2:

Use the WinAPI version of the function GetFileSize() as follows:

procedure CardinalsToI64(var I: Int64; const LowPart, HighPart: Cardinal);
begin
  TULargeInteger(I).LowPart := LowPart;
  TULargeInteger(I).HighPart := HighPart;
end;

{ ... }
var
  fLOdword: dword;
  fHIdword: dword;
  FFilesize: Int64;
  FFileHandle: THandle;
begin
  FFileHandle := CreateFile(PChar(FFileName), GENERIC_READ, FILE_SHARE_READ, nil,
    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  fLOdword := GetFileSize(FFileHandle, @fHIdword);
  CardinalsToI64(FFilesize, fLOdword, fHIdword);

Nincsenek megjegyzések:

Megjegyzés küldése