Format a number of bytes in KB, MB, GB, and so forth in C#
This example makes a couple of extension method that convert numeric values into strings representing a number of bytes in bytes, KB, MB, and so forth.
The first method adds a ToFileSizeApi function to the long class. It starts by including the following using statement:
The StrFormatByteSize has one drawback: it only works with sizes up to petabytes. Admittedly this is a lot but you might want to display values that are even larger. To handle larger file sizes, the MyExtensions class also provides an extension method that converts doubles into file size strings and handles values up to yottabytes. (As of 2009, the sum of the storage on every computer in the world is estimated at around 500 exabytes so this should be enough for a while, at least if you're measuring real file sizes. For more information, see Wikipedia's yottabyte page.)
using System.Runtime.InteropServices;Then the MyExtensions class includes this declaration of the StrFormatByteSize API function:
[DllImport("Shlwapi.dll", CharSet = CharSet.Auto)]
public static extern Int32 StrFormatByteSize(
long fileSize,
[MarshalAs(UnmanagedType.LPTStr)] StringBuilder buffer,
int bufferSize);
This API function returns a string similar to the one that Windows uses when it needs to display the size of a file, for example, in Windows Explorer.
To make using the API function easy, the class includes this extension method:
// Return a file size created by the StrFormatByteSize API function.
public static string ToFileSizeApi(this long file_size)
{
StringBuilder sb = new StringBuilder(20);
StrFormatByteSize(file_size, sb, 20);
return sb.ToString();
}
The StrFormatByteSize has one drawback: it only works with sizes up to petabytes. Admittedly this is a lot but you might want to display values that are even larger. To handle larger file sizes, the MyExtensions class also provides an extension method that converts doubles into file size strings and handles values up to yottabytes. (As of 2009, the sum of the storage on every computer in the world is estimated at around 500 exabytes so this should be enough for a while, at least if you're measuring real file sizes. For more information, see Wikipedia's yottabyte page.)
// Return a string describing the value as a file size.The ToFileSize extension method compares the value to larger and larger powers of 1024. When it finds a power of 1024 greater than or equal to the value, the code divides the value by the next smaller power and adds the appropriate suffix. The ThreeNonZeroDigits function returns up to three non-zero digits for a number.
// For example, 1.23 MB.
public static string ToFileSize(this double value)
{
string[] suffixes = { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
for (int i = 0; i < suffixes.Length; i++)
{
if (value <= (Math.Pow(1024, i + 1)))
{
return ThreeNonZeroDigits(value / Math.Pow(1024, i)) + " " + suffixes[i];
}
}
return ThreeNonZeroDigits(value / Math.Pow(1024, suffixes.Length - 1)) +
" " + suffixes[suffixes.Length - 1];
}
// Return the value formatted to include at most threeNote that there is some ambiguity here. Some people define a kilobyte as 1024 bytes but others (particularly disk drive manufacturers who like to make you think your drive is bigger than it really is) define it as 1000 bytes. The ToFileSize method assumes a kilobyte is 1024 bytes. You can easily change this if you want to work with 1000 byte kilobytes. Note also that the StrFormatByteSize API function doesn't return the same result as ToFileSize. For some reason, the API function seems to be truncating. For example, 12,345,000 is approximately 11.77 MB but StrFormatByteSize returns 11.7 MB instead of 11.8 MB. The example program displays several numbers with their file size strings using both of these extension methods so you can compare the results.
// non-zero digits and at most two digits after the
// decimal point. Examples:
// 1
// 123
// 12.3
// 1.23
// 0.12
private static string ThreeNonZeroDigits(double value)
{
if (value >= 100)
{
// No digits after the decimal.
return value.ToString("0,0");
}
else if (value >= 10)
{
// One digit after the decimal.
return value.ToString("0.0");
}
else
{
// Two digits after the decimal.
return value.ToString("0.00");
}
}



Comments