Search code examples
delphimathfilesize

Getting File Sizes > And then Getting the Total Size?


This should be easy, but I cannot seem to get it right as I seem to be confusing myself and converting to and from strings, integers and floats and whatnot.

Basically, I am populating a TListView with FileNames in one column, and in another column returning the File Size to the corresponding FileName. I am using a rather neat function found from here, which looks like this:

function FileSizeStr ( filename: string ): string;
const
//   K = Int64(1000);     // Comment out this line OR
  K = Int64(1024);     // Comment out this line
  M = K * K;
  G = K * M;
  T = K * G;
var
  size: Int64;
  handle: integer;
begin
  handle := FileOpen(filename, fmOpenRead);
  if handle = -1 then
    result := 'Unable to open file ' + filename
  else try
    size := FileSeek ( handle, Int64(0), 2 );
    if size < K then result := Format ( '%d bytes', [size] )
    else if size < M then result := Format ( '%f KB', [size / K] )
    else if size < G then result := Format ( '%f MB', [size / M] )
    else if size < T then result := Format ( '%f GB', [size / G] )
    else result := Format ( '%f TB', [size / T] );
  finally
    FileClose ( handle );
  end;
end;

This returns values such as: 235.40 KB

So with the above, my TListView may be populated like so:

enter image description here

Now in the Label Data Size, I would like to return the Total Size of the Files in the Listview, so in this example, the values from the Size column would need adding up to return the Total Size, something like:

1.28 MB + 313.90 KB + 541.62 KB + 270.96 KB

Obviously it cannot be added on just like that, because the values contain decimal points, some values may be in Kb, and other in Mb etc. This is my problem, I cannot think of an easy solution to add (get) the Total Size of the Files, and then return it in the same formatted string as shown.

I would really appreciate some insight or tips how to work with this kind of data, I am just endlessly confusing myself with different conversions etc and not really sure which way to do this.

Many Thanks in advance :)

UPDATE 1

Following the advice from Marc B, I changed the function to the following which seems to work:

var
  iFileSize: Int64;

implementation

function GetSizeOfFile(FileName: string): Int64;
var
  Handle: Integer;
begin
  Handle := FileOpen(FileName, fmOpenRead);

  if Handle = -1 then
    MessageDlg('Unable to open file ' + FileName, mtError, [mbOk], 0)
  else try
    iFileSize := iFileSize + FileSeek(Handle, Int64(0), 2);
  finally
    FileClose(Handle);
  end;

  Result := iFileSize;
end;

function FormatFileSize(AValue: Int64): string;
const
  K = Int64(1024);
  M = K * K;
  G = K * M;
  T = K * G;
begin
  if AValue < K then Result := Format ( '%d bytes', [AValue] )
  else if AValue < M then Result := Format ( '%f KB', [AValue / K] )
  else if AValue < G then Result := Format ( '%f MB', [AValue / M] )
  else if AValue < T then Result := Format ( '%f GB', [AValue / G] )
  else Result := Format ( '%f TB', [AValue / T] );
end;

It may be useful for anyone else should they need it :)

UPDATE 2

Additionally, see the answer Ken White posted which provides more valuable information, and a cleaner update of the GetSizeOfFile function, which works great:

enter image description here


Solution

  • Separate the "get file information" from the "format the size string" into two separate functions. The file information function fetches the file size and adds it to a running total, THEN calls the formatting function to convert the simple integer into the "nice" string.