Converting Bytes to Gb in C#?
I Was Refactoring Some Old Code and Came Across the Following Line of Code to Convert Bytes to Gb. Decimal Gb = Kb / 1024 / 1024 / 1024; Is There a Better Way...
I was refactoring some old code and came across the following line of code to convert bytes to GB.
decimal GB = KB / 1024 / 1024 / 1024;
Is there a better way to refactor the following piece of code?
Update
I meant to say bytes to Gigabytes. I gave wrong information.
13 Answers
I developed this method here, works up to TB.
private static string FormatBytes(long bytes)
{
string[] Suffix = { "B", "KB", "MB", "GB", "TB" };
int i;
double dblSByte = bytes;
for (i = 0; i < Suffix.Length && bytes >= 1024; i++, bytes /= 1024)
{
dblSByte = bytes / 1024.0;
}
return String.Format("{0:0.##} {1}", dblSByte, Suffix[i]);
}
If exact precision is not important, use double:
double gb = kb / 1048576D
Agree with Pavel here - there's not really any need to refactor this code... in fact, if this is the biggest problem in your codebase, I think you might be sitting on the most well-written software ever.
The original code is succinct, easy to read, and with reasonable variable names, self-documenting; I wouldn't change it.
If you absolutely must refactor, you could create a set of extension methods on the numeric types:
public static double BytesToKilobytes(this Int32 bytes)
{
return bytes / 1024d;
}
public static double BytesToMegabytes(this Int32 bytes)
{
return bytes / 1024d / 1024d;
}
public static double KilobytesToBytes(this double kilobytes)
{
return kilobytes * 1024d;
}
//You can then do something like:
double filesize = 32.5d;
double bytes = filesize.KilobytesToBytes();
But unless your code does virtually nothing but convert bytes to kilobytes etc, all this will really do is clutter up Intellisense for no real gain.
/// <summary>
/// Function to convert the given bytes to either Kilobyte, Megabyte, or Gigabyte
/// </summary>
/// <param name="bytes">Double -> Total bytes to be converted</param>
/// <param name="type">String -> Type of conversion to perform</param>
/// <returns>Int32 -> Converted bytes</returns>
/// <remarks></remarks>
public static double ConvertSize(double bytes, string type)
{
try
{
const int CONVERSION_VALUE = 1024;
//determine what conversion they want
switch (type)
{
case "BY":
//convert to bytes (default)
return bytes;
case "KB":
//convert to kilobytes
return (bytes / CONVERSION_VALUE);
case "MB":
//convert to megabytes
return (bytes / CalculateSquare(CONVERSION_VALUE));
case "GB":
//convert to gigabytes
return (bytes / CalculateCube(CONVERSION_VALUE));
default:
//default
return bytes;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return 0;
}
}
/// <summary>
/// Function to calculate the square of the provided number
/// </summary>
/// <param name="number">Int32 -> Number to be squared</param>
/// <returns>Double -> THe provided number squared</returns>
/// <remarks></remarks>
public static double CalculateSquare(Int32 number)
{
return Math.Pow(number, 2);
}
/// <summary>
/// Function to calculate the cube of the provided number
/// </summary>
/// <param name="number">Int32 -> Number to be cubed</param>
/// <returns>Double -> THe provided number cubed</returns>
/// <remarks></remarks>
public static double CalculateCube(Int32 number)
{
return Math.Pow(number, 3);
}
//Sample Useage
String Size = "File is " + ConvertSize(250222,"MB") + " Megabytes in size"
Personally I'd write it like this: decimal GB = KB / (1024 * 1024); but there's really no need to refactor the code as written.
Well, the formula is wrong (there's only about a million kilobytes in a gigabyte, not a thousand million) but, other than that, it's fine. Anyone used to working with these numbers will know what it means.
One thing I would watch out for (and I don't know if this is a problem with C#) is that a compiler may not be able to optimize the x/1024/1024 if x is not a basic type. With C and integers, the compiler would quite easily turn that into a "blindingly-fast-shift-right-by-20-bits" instruction.
If decimal is a class rather than a basic type, the compiler may have to do two divide operations. Whether this has any real impact on speed (or even whether it happens at all) is outside of my sphere of knowledge.
One thing I'd consider changing is the actual variable names. It makes no real difference to the compiled code but I prefer longer variable names rather than abbreviations, so I'd opt for kiloBytes/gigaBytes or something like that. KB/GB is too easy to get confused with constants, depending on your coding standards.
In theory, this is faster (precomputing the constant to do multiplication instead of division). It's probably not used often enough to matter, but just in case.
double const KbToGbFactor = 1d / 1024 /1024;
double gb = kb * KbToGbFactor;
I needed it the other way around, convert from 3rd party component literal size in words (e.g. "0 bytes", "1.1 MB") into generic size in bytes. so I used it this way:
private static long UnformatBytes(string sizeInWords)
{
if(string.IsNullOrWhiteSpace(sizeInWords))
return -1;
string size = sizeInWords.Split(' ').FirstOrDefault();
double result;
if (string.IsNullOrWhiteSpace(size) || !double.TryParse(size, out result))
{
Debugger.Break();
return -1;
}
int pow;
if (sizeInWords.IndexOf("byte", StringComparison.OrdinalIgnoreCase) > -1)
pow = 0;
else if (sizeInWords.IndexOf("kb", StringComparison.OrdinalIgnoreCase) > -1)
pow = 1;
else if (sizeInWords.IndexOf("mb", StringComparison.OrdinalIgnoreCase) > -1)
pow = 2;
else if (sizeInWords.IndexOf("gb", StringComparison.OrdinalIgnoreCase) > -1)
pow = 3;
else if (sizeInWords.IndexOf("tb", StringComparison.OrdinalIgnoreCase) > -1)
pow = 4;
else
return -1;
return System.Convert.ToInt64((result * Math.Pow(1024, pow)));
}
I wrote a small utility class that performs conversions between units, hth..
#region StorageDifferential
/// <summary>
/// Converts between Base 2 or Base 10 storage units [TB, GB, MB, KB, Bytes]
/// </summary>
public enum Differential : int
{
/// <summary>
/// Convert Bytes to Kilobytes
/// </summary>
ByteToKilo,
/// <summary>
/// Convert Bytes to Megabytes
/// </summary>
ByteToMega,
/// <summary>
/// Convert Bytes to Gigabytes
/// </summary>
ByteToGiga,
/// <summary>
/// Convert Bytes to Teraytes
/// </summary>
ByteToTera,
/// <summary>
/// Convert Kilobytes to Bytes
/// </summary>
KiloToByte,
/// <summary>
/// Convert Kilobytes to Megabytes
/// </summary>
KiloToMega,
/// <summary>
/// Convert Kilobytes to Gigabytes
/// </summary>
KiloToGiga,
/// <summary>
/// Convert Kilobytes to Terabytes
/// </summary>
KiloToTera,
/// <summary>
/// Convert Megabytes to Bytes
/// </summary>
MegaToByte,
/// <summary>
/// Convert Megabytes to Kilobytes
/// </summary>
MegaToKilo,
/// <summary>
/// Convert Megabytes to Gigabytes
/// </summary>
MegaToGiga,
/// <summary>
/// Convert Megabytes to Terabytes
/// </summary>
MegaToTera,
/// <summary>
/// Convert Gigabytes to Bytes
/// </summary>
GigaToByte,
/// <summary>
/// Convert Gigabytes to Kilobytes
/// </summary>
GigaToKilo,
/// <summary>
/// Convert Gigabytes to Megabytes
/// </summary>
GigaToMega,
/// <summary>
/// Convert Gigabytes to Terabytes
/// </summary>
GigaToTerra,
/// <summary>
/// Convert Terabyte to Bytes
/// </summary>
TeraToByte,
/// <summary>
/// Convert Terabyte to Kilobytes
/// </summary>
TeraToKilo,
/// <summary>
/// Convert Terabytes to Megabytes
/// </summary>
TeraToMega,
/// <summary>
/// Convert Terabytes to Gigabytes
/// </summary>
TeraToGiga,
}
#endregion
#region Storage Sizes
/// <summary>
/// Enumeration of recognized storage sizes [in Bytes]
/// </summary>
public enum StorageSizes : long
{
/// <summary>
/// Base 10 Conversion
/// </summary>
KILOBYTE = 1000,
MEGABYTE = 1000000,
GIGABYTE = 1000000000,
TERABYTE = 1000000000000,
/// <summary>
/// Base 2 Conversion
/// </summary>
KIBIBYTE = 1024,
MEBIBYTE = 1048576,
GIBIBYTE = 1073741824,
TEBIBYTE = 1099511627776,
}
#endregion
#region StorageBase
/// <summary>
/// Storage powers 10 based or 1024 based
/// </summary>
public enum StorageBase : int
{
/// <summary>
/// 1024 Base power, Typically used in memory measurements
/// </summary>
BASE2,
/// <summary>
/// 10 Base power, Used in storage mediums like harddrives
/// </summary>
BASE10,
}
#endregion
/// <summary>
/// Convert between base 1024 storage units [TB, GB, MB, KB, Byte]
/// </summary>
public static class StorageConverter
{
/// <summary>
/// Convert between base 1024 storage units [TB, GB, MB, KB, Byte]
/// </summary>
/// <param name="SizeDifferential">Storage conversion differential [enum]</param>
/// <param name="UnitSize">Size as mutiple of unit type units [double]</param>
/// <param name="BaseUnit">Size of the base power [enum]</param>
/// <returns>Converted unit size [double]</returns>
public static double Convert(Differential SizeDifferential, double UnitSize, StorageBase BaseUnit = StorageBase.BASE10)
{
if (UnitSize < 0.000000000001) return 0;
double POWER1 = 1000;
double POWER2 = 1000000;
double POWER3 = 1000000000;
double POWER4 = 1000000000000;
if (BaseUnit == StorageBase.BASE2)
{
POWER1 = 1024;
POWER2 = 1048576;
POWER3 = 1073741824;
POWER4 = 1099511627776;
}
switch (SizeDifferential)
{
case Differential.ByteToKilo:
return UnitSize / POWER1;
case Differential.ByteToMega:
return UnitSize / POWER2;
case Differential.ByteToGiga:
return UnitSize / POWER3;
case Differential.ByteToTera:
return UnitSize / POWER4;
case Differential.KiloToByte:
return UnitSize * POWER1;
case Differential.KiloToMega:
return UnitSize / POWER1;
case Differential.KiloToGiga:
return UnitSize / POWER2;
case Differential.KiloToTera:
return UnitSize / POWER3;
case Differential.MegaToByte:
return UnitSize * POWER2;
case Differential.MegaToKilo:
return UnitSize * POWER1;
case Differential.MegaToGiga:
return UnitSize / POWER1;
case Differential.MegaToTera:
return UnitSize / POWER2;
case Differential.GigaToByte:
return UnitSize * POWER3;
case Differential.GigaToKilo:
return UnitSize * POWER2;
case Differential.GigaToMega:
return UnitSize * POWER1;
case Differential.GigaToTerra:
return UnitSize / POWER1;
case Differential.TeraToByte:
return UnitSize * POWER4;
case Differential.TeraToKilo:
return UnitSize * POWER3;
case Differential.TeraToMega:
return UnitSize * POWER2;
case Differential.TeraToGiga:
return UnitSize * POWER1;
}
return 0;
}
}
This is a little improvement of the good JLopez's answer. Here you can choose to have or not the units indication and the kilo unit is written with the lowercase "k" (the uppercase one is for Kelvin)
//note: this is the JLopez answer!!
/// <summary>
/// Return size in human readable form
/// </summary>
/// <param name="bytes">Size in bytes</param>
/// <param name="useUnit ">Includes measure unit (default: false)</param>
/// <returns>Readable value</returns>
public static string FormatBytes(long bytes, bool useUnit = false)
{
string[] Suffix = { " B", " kB", " MB", " GB", " TB" };
double dblSByte = bytes;
int i;
for (i = 0; i < Suffix.Length && bytes >= 1024; i++, bytes /= 1024)
{
dblSByte = bytes / 1024.0;
}
return $"{dblSByte:0.##}{(useUnit ? Suffix[i] : null)}";
}
To make sure that the compiler pre-calculates the divisors:
decimal GB = KB / (1024 * 1024);
Note that you are actually calculating GiB (gibibyte), not GB (gigabyte). If you really want to calculate GB, that would be:
decimal GB = KB / (1000 * 1000);
public static string BytesToString(this long bytes, string format = "#,##0.00") {
var unitstr = new string[] { "B", "KB", "MB", "GB", "TB" };
var bytesd = Convert.ToDouble(bytes);
var unit = 0;
while (bytesd / 1024D > 1 && unit < unitstr.Length) {
unit++; bytesd /= 1024D;
}
return string.Format("{0:" + format + "}{1}", bytesd, unitstr[unit]);
}
#region AutoFileSize
public string AutoFileSize(long number)
{
double tmp = number;
string suffix = " B ";
if (tmp > 1024) { tmp = tmp / 1024; suffix = " KB"; }
if (tmp > 1024) { tmp = tmp / 1024; suffix = " MB"; }
if (tmp > 1024) { tmp = tmp / 1024; suffix = " GB"; }
if (tmp > 1024) { tmp = tmp / 1024; suffix = " TB"; }
return tmp.ToString("n") + suffix;
}
#endregion
long number = (long)fu.PostedFile.ContentLength;