Inno Setup get directory size including subdirecto

2019-06-07 06:07发布

问题:

I am trying to write a function that returns the size of a directory. I have written the following code, but it is not returning the correct size. For example, when I run it on the {pf} directory it returns 174 bytes, which is clearly wrong as this directory is multiple Gigabytes in size. Here is the code I have:

function GetDirSize(DirName: String): Int64;
var
  FindRec: TFindRec;
begin
  if FindFirst(DirName + '\*', FindRec) then
    begin
      try
        repeat
          Result := Result + (Int64(FindRec.SizeHigh) shl 32 + FindRec.SizeLow);
        until not FindNext(FindRec);
      finally
        FindClose(FindRec);
      end;
    end
  else
    begin
      Result := -1;
    end;
end;

I suspect that the FindFirst function does not include subdirectories, which is why I am not getting the correct result. Therefore, how can I return the correct size of a directory i.e. including all files in all subdirectories, the same as selecting Properties on a Folder in Windows Explorer? I am using FindFirst as the function needs to support directory sizes over 2GB.

回答1:

The FindFirst does include subdirectories, but it won't get you their sizes.

You have to recurse into subdirectories and calculate the total size file by file, similarly as to for example Inno Setup: copy folder, subfolders and files recursively in Code section.

function GetDirSize(Path: String): Int64;
var
  FindRec: TFindRec;
  FilePath: string;
  Size: Int64;
begin
  if FindFirst(Path + '\*', FindRec) then
  begin
    Result := 0;
    try
      repeat
        if (FindRec.Name <> '.') and (FindRec.Name <> '..') then
        begin
          FilePath := Path + '\' + FindRec.Name;
          if (FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY) <> 0 then
          begin
            Size := GetDirSize(FilePath);
          end
            else
          begin
            Size := Int64(FindRec.SizeHigh) shl 32 + FindRec.SizeLow;
          end;
          Result := Result + Size;
        end;
      until not FindNext(FindRec);
    finally
      FindClose(FindRec);
    end;
  end
    else
  begin
    Log(Format('Failed to list %s', [Path]));
    Result := -1;
  end;
end;

For Int64, you need Unicode version of Inno Setup, what you should be using in any case. Only if you have a very good reason to stick with Ansi version, you can replace the Int64 with Integer, but than you are limited to 2 GB.