How to Pretty Format a Number as File Size in C#, PHP and Delphi

This function will pretty format a given number as file size, for example, convert 1000000 to 1MB, 3523 to 3k and so on.

By Tim Trott | C# ASP.Net MVC | January 24, 2009

Pretty Format a Number as File Size in C#

This short snippet can be used to pretty format a number of a file size (in bytes) into a pretty string that includes file size metric. This snippet is a modified version of the first posting which has been refactored by Ben Laan (see comments below). The original script was copied from some other website quite a while ago, cannot remember where from, but I have used it extensively and thought I would share this useful method. If you know who the original author is please let me know.

C#
public string FormatBytes(long bytes)
{
  const int scale = 1024;
  string[] orders = new string[] { "GB", "MB", "KB", "Bytes" };
  long max = (long)Math.Pow(scale, orders.Length - 1);

  foreach (string order in orders)
  {
    if ( bytes > max )
      return string.Format("{0:##.##} {1}", decimal.Divide( bytes, max ), order);

    max /= scale;
  }
  return "0 Bytes";
}

The original code:

C#
public string FormatBytes(int Bytes)
{
  string filesize;
  if (Bytes >= 1073741824)
  {
    decimal size = decimal.Divide(Bytes, 1073741824);
    filesize = string.Format("{0:##.##} GB", size);
  }
  else if (Bytes >= 1048576)
  {
    decimal size = decimal.Divide(Bytes, 1048576);
    filesize = string.Format("{0:##.##} MB", size);
  }
  else if (Bytes >= 1024)
  {
    decimal size = decimal.Divide(Bytes, 1024);
    filesize = string.Format("{0:##.##} KB", size);
  }
  else if (Bytes > 0 &amp; Bytes < 1024)
  {
    decimal size = Bytes;
    filesize = string.Format("{0:##.##} Bytes", size);
  }
  else
  {
    filesize = "0 Bytes";
  }
  return filesize;
}

Pretty Format a Number as File Size in PHP

Code to pretty format a number as file size

php
function formatbytes($val, $digits = 3, $mode = "SI", $bB = "B")
{ 
  $si = array("", "k", "M", "G", "T", "P", "E", "Z", "Y");
  $iec = array("", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi");

  switch(strtoupper($mode)) 
  {
      case "SI" : $factor = 1000; $symbols = $si; break;
      case "IEC" : $factor = 1024; $symbols = $iec; break;
      default : $factor = 1000; $symbols = $si; break;
  }

  switch($bB) 
  {
      case "b" : $val *= 8; break;
      default : $bB = "B"; break;
  }
  
  for($i=0;$i<count($symbols)-1 && $val>=$factor;$i++)
      $val /= $factor;
  
  $p = strpos($val, ".");
  if($p !== false && $p > $digits) 
    $val = round($val);
  elseif($p !== false) 
    $val = round($val, $digits-$p);
  
  return round($val, $digits) . " " . $symbols[$i] . $bB;
}

Simply pass in an integer file size and it will return a value to 3 significant figures using SI notation. You can increase the number of figures by changing the second parameter in the call and the mode in the last two.

Example Formatting Number as File Size

php
$filename = 'somefile.txt';
echo $filename . ': ' . filesize($filename) . ' bytes';

Will output "somefile.txt: 219543 bytes"

php
$filename = 'somefile.txt';
echo $filename . ': ' . formatbytes(filesize($filename));

Will output "somefile.txt: 219 kB"

Pretty Format a Number as File Size in Delphi

Delphi Get File Size procedure will get the file size, in bytes, of a specified filename. Useful function for file-handing in Pascal.

pascal
function GetFileSize( FileName:string ): int64;
  var
    fh: integer;
    fi: TByHandleFileInformation;
  begin
  result := 0;
  fh := fileopen( FileName, fmOpenRead );
    try
    if GetFileInformationByHandle( fh, fi ) then
      begin
      result := fi.nFileSizeHigh;
      result := result shr 32 + fi.nFileSizeLow;
      end;
    finally
    fileclose( fh );
    end;
  end;

This function returns the filesize in bytes. If you want format that for users, such as showing megabytes or gigabytes you can use this function as well.

pascal
uses
  Math;

function ConvertBytes(Bytes: Int64): string;
const
  Description: Array [0 .. 8] of string = ('Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
var
  i: Integer;
begin
  i := 0;

  while Bytes > Power(1024, i + 1) do
    Inc(i);

  Result := FormatFloat('###0.##', Bytes / Power(1024, i)) + #32 + Description[i];
end;
Was this article helpful to you?
 

Related ArticlesThese articles may also be of interest to you

CommentsShare your thoughts in the comments below

If you enjoyed reading this article, or it helped you in some way, all I ask in return is you leave a comment below or share this page with your friends. Thank you.

This post has 11 comment(s). Why not join the discussion!

We respect your privacy, and will not make your email public. Learn how your comment data is processed.

  1. KE

    On Sunday 7th of December 2014, Ken said

    I think the newer solution is slower and incorrect.

    C#
    [Fact]
    public void ShouldFormatGigabytes()
    {
        const long sut = 1 * 1024 * 1024 * 1024;
        Assert.Equal("1 GB", FormatBytes(sut));
    }

    Actual: 1024 MB

  2. BK

    On Thursday 31st of March 2011, BK said

    Another refactoring without the loop (in VB):

    vb
    Private Function FormatBytes(ByVal bytes As Long) As String
    Const scale = 1024
    Dim orders As String() = New String() {"", "K", "M", "G", "T", "P", "E"}
    
    Dim rank = Math.Floor(Math.Log(bytes, scale))
    If rank >= orders.Length Then rank -= 1
    Return String.Format("{0:##.##} {1}B", bytes / Math.Pow(scale, rank), orders(rank))
    End Function
  3. PA

    On Monday 6th of December 2010, Paul said

    C#
    if (bytes == max) return string.Format("1 {0}", order);
  4. SH

    On Tuesday 9th of March 2010, Steven Hartgers said

    I got the ultimate solution:

    C#
    return (String.Format("{0:##.##0}",
      Bytes >= 1073741824 ? decimal.Divide(Bytes, 1073741824) + "GB" :
      Bytes >= 1048576 ? decimal.Divide(Bytes, 1048576) + "MB" :
      Bytes >= 1024 ? decimal.Divide(Bytes, 1024) + "KB" :
      Bytes > 0 &amp; Bytes < 1024 ? Bytes + "Bytes" : 0 + "0 Bytes"
    ));

    Happy formating :)

  5. IA

    On Monday 22nd of February 2010, ian said

    So I used this in a console app recently as well, here was my function.. just to wrap it up..

    C#
    static string FormatBytes(long bytes)
    {
    const long scale = 1024;
    string[] orders = new string[]{ "YB", "ZB", "EB", "PB", "TB", "GB", "MB", "KB", "Bytes" };
    var max = (long)Math.Pow(scale, (orders.Length - 1));
    foreach (string order in orders)
    {
    if (bytes > max)
    return string.Format("{0:##.##} {1}", Decimal.Divide(bytes, max), order);
    max /= scale;
    }
                return "0 Bytes";
    }
    1. IA

      On Monday 22nd of February 2010, ian replied

      Okay so this actually only works up to the EB's, it kind of looks like somewhere between EB's and ZB's we hit the max value for the long data type, and the previous function would return just "YB" for all of the string values. So I modified the orders array to this:

      string[] orders = new string[]{ "EB", "PB", "TB", "GB", "MB", "KB", "Bytes" };

      You could try a different data type, but I'm not measuring anything larger than EB's anyways.

  6. RO

    On Thursday 11th of February 2010, Ross said

    Hi, nice code, thanks!

    I also changed this line to do a little future proofing for Diomede Storage. :)

    string[] orders = new string[] { "YB", "ZB", "EB", "PB", "TB", "GB", "MB", "KB", "Bytes" };

    -- Ross

    1. SH

      On Thursday 20th of December 2012, Shimmy replied

      @Ross what about Brontobytes? :-)

  7. IA

    On Wednesday 10th of February 2010, Ian said

    thanks code worked great. if your bytes are displayed in MB like mine were all you have to do is modify the scale..mine looked something like scale = (1024/10) or you could go the other way scale = 10240

    awesome code thanks a bunch.

  8. BL

    On Tuesday 5th of May 2009, Ben Laan said

    This code has 4 repeating blocks! Sounds like it needs a good refactoring:

    C#
    public string FormatBytesNew( long bytes )
    {
        const int scale = 1024;
    
        var orders = new[] { "GB", "MB", "KB", "Bytes" };
        var max = (long) Math.Pow( scale, orders.Length - 1 );
    
        foreach ( var order in orders )
        {
            if ( bytes > max )
                return string.Format( "{0:##.##} {1}", Decimal.Divide( bytes, max ), order );
    
            max /= scale;
        }
        return "0 Bytes";
    }
  9. Tim Trott

    On Tuesday 5th of May 2009, Tim Trott  Post Author said

    Hi ben,

    Thanks for the refactor!

    I wasn't completely happy with the code, especially the hard coded byte values; however I copied if from the somewhere on the web and just carried on using it. "If it ain't broke, don't fix it".

    I will probably give your version a try though!

    Thanks