¿.NET proporciona una manera fácil de convertir bytes a KB, MB, GB, etc.?

Me pregunto si .NET proporciona una forma limpia de hacer esto:

int64 x = 1000000; string y = null; if (x / 1024 == 0) { y = x + " bytes"; } else if (x / (1024 * 1024) == 0) { y = string.Format("{0:n1} KB", x / 1024f); } 

etc …

Aquí hay una forma bastante concisa de hacer esto:

 static readonly string[] SizeSuffixes = { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" }; static string SizeSuffix(Int64 value, int decimalPlaces = 1) { if (decimalPlaces < 0) { throw new ArgumentOutOfRangeException("decimalPlaces"); } if (value < 0) { return "-" + SizeSuffix(-value); } if (value == 0) { return string.Format("{0:n" + decimalPlaces + "} bytes", 0); } // mag is 0 for bytes, 1 for KB, 2, for MB, etc. int mag = (int)Math.Log(value, 1024); // 1L << (mag * 10) == 2 ^ (10 * mag) // [ie the number of bytes in the unit corresponding to mag] decimal adjustedSize = (decimal)value / (1L << (mag * 10)); // make adjustment when the value is large enough that // it would round up to 1000 or more if (Math.Round(adjustedSize, decimalPlaces) >= 1000) { mag += 1; adjustedSize /= 1024; } return string.Format("{0:n" + decimalPlaces + "} {1}", adjustedSize, SizeSuffixes[mag]); } 

Y aquí está la implementación original que sugerí, que puede ser un poco más lenta, pero un poco más fácil de seguir:

 static readonly string[] SizeSuffixes = { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" }; static string SizeSuffix(Int64 value, int decimalPlaces = 1) { if (value < 0) { return "-" + SizeSuffix(-value); } int i = 0; decimal dValue = (decimal)value; while (Math.Round(dValue, decimalPlaces) >= 1000) { dValue /= 1024; i++; } return string.Format("{0:n" + decimalPlaces + "} {1}", dValue, SizeSuffixes[i]); } Console.WriteLine(SizeSuffix(100005000L)); 

Consulte la biblioteca ByteSize . Es el System.TimeSpan para bytes!

Maneja la conversión y el formato para usted.

 var maxFileSize = ByteSize.FromKiloBytes(10); maxFileSize.Bytes; maxFileSize.MegaBytes; maxFileSize.GigaBytes; 

También realiza representación y análisis de cadenas.

 // ToString ByteSize.FromKiloBytes(1024).ToString(); // 1 MB ByteSize.FromGigabytes(.5).ToString(); // 512 MB ByteSize.FromGigabytes(1024).ToString(); // 1 TB // Parsing ByteSize.Parse("5b"); ByteSize.Parse("1.55B"); 

Como todos los demás publican sus métodos, pensé que publicaría el método de extensión que suelo usar para esto:

EDITAR: agregó variantes int / long … y corrigió un error tipográfico copypasta …

 public static class Ext { private const long OneKb = 1024; private const long OneMb = OneKb * 1024; private const long OneGb = OneMb * 1024; private const long OneTb = OneGb * 1024; public static string ToPrettySize(this int value, int decimalPlaces = 0) { return ((long)value).ToPrettySize(decimalPlaces); } public static string ToPrettySize(this long value, int decimalPlaces = 0) { var asTb = Math.Round((double)value / OneTb, decimalPlaces); var asGb = Math.Round((double)value / OneGb, decimalPlaces); var asMb = Math.Round((double)value / OneMb, decimalPlaces); var asKb = Math.Round((double)value / OneKb, decimalPlaces); string chosenValue = asTb > 1 ? string.Format("{0}Tb",asTb) : asGb > 1 ? string.Format("{0}Gb",asGb) : asMb > 1 ? string.Format("{0}Mb",asMb) : asKb > 1 ? string.Format("{0}Kb",asKb) : string.Format("{0}B", Math.Round((double)value, decimalPlaces)); return chosenValue; } } 

Lo resolvería usando Extension methods , función Enums y Enums :

 public static class MyExtension { public enum SizeUnits { Byte, KB, MB, GB, TB, PB, EB, ZB, YB } public static string ToSize(this Int64 value, SizeUnits unit) { return (value / (double)Math.Pow(1024, (Int64)unit)).ToString("0.00"); } } 

y úsalo como:

 string h = x.ToSize(MyExtension.SizeUnits.KB); 

No. Principalmente porque es una necesidad bastante específica, y hay demasiadas variaciones posibles. (¿Es “KB”, “Kb” o “Ko”? ¿Es un megabyte de 1024 * 1024 bytes o 1024 * 1000 bytes? Sí, ¡algunos lugares lo usan!)

Aquí hay una opción que es más fácil de extender que la suya, pero no, no hay ninguna integrada en la biblioteca.

 private static List suffixes = new List { " B", " KB", " MB", " GB", " TB", " PB" }; public static string Foo(int number) { for (int i = 0; i < suffixes.Count; i++) { int temp = number / (int)Math.Pow(1024, i + 1); if (temp == 0) return (number / (int)Math.Pow(1024, i)) + suffixes[i]; } return number.ToString(); } 

La versión corta de la respuesta más votada tiene problemas con los valores de TB.

Lo ajusté adecuadamente para manejar también los valores de tb y aún sin un bucle y también agregué un pequeño error para verificar valores negativos. Aquí está mi solución:

 static readonly string[] SizeSuffixes = { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" }; static string SizeSuffix(long value, int decimalPlaces = 0) { if (value < 0) { throw new ArgumentException("Bytes should not be negative", "value"); } var mag = (int)Math.Max(0, Math.Log(value, 1024)); var adjustedSize = Math.Round(value / Math.Pow(1024, mag), decimalPlaces); return String.Format("{0} {1}", adjustedSize, SizeSuffixes[mag]); } 
  private string GetFileSize(double byteCount) { string size = "0 Bytes"; if (byteCount >= 1073741824.0) size = String.Format("{0:##.##}", byteCount / 1073741824.0) + " GB"; else if (byteCount >= 1048576.0) size = String.Format("{0:##.##}", byteCount / 1048576.0) + " MB"; else if (byteCount >= 1024.0) size = String.Format("{0:##.##}", byteCount / 1024.0) + " KB"; else if (byteCount > 0 && byteCount < 1024.0) size = byteCount.ToString() + " Bytes"; return size; } private void btnBrowse_Click(object sender, EventArgs e) { if (openFile1.ShowDialog() == DialogResult.OK) { FileInfo thisFile = new FileInfo(openFile1.FileName); string info = ""; info += "File: " + Path.GetFileName(openFile1.FileName); info += Environment.NewLine; info += "File Size: " + GetFileSize((int)thisFile.Length); label1.Text = info; } } 

Esta es una forma de hacerlo también (El número 1073741824.0 es de 1024 * 1024 * 1024 también conocido como GB)

He combinado algunas de las respuestas aquí en dos métodos que funcionan muy bien. El segundo método a continuación convertirá desde una cadena de bytes (como 1.5.1 GB) a bytes (como 1621350140) como un valor de tipo largo. Espero que esto sea útil para otros que buscan una solución para convertir bytes a una cadena y volver a convertirlos en bytes.

 public static string BytesAsString(float bytes) { string[] suffix = { "B", "KB", "MB", "GB", "TB" }; int i; double doubleBytes = 0; for (i = 0; (int)(bytes / 1024) > 0; i++, bytes /= 1024) { doubleBytes = bytes / 1024.0; } return string.Format("{0:0.00} {1}", doubleBytes, suffix[i]); } public static long StringAsBytes(string bytesString) { if (string.IsNullOrEmpty(bytesString)) { return 0; } const long OneKb = 1024; const long OneMb = OneKb * 1024; const long OneGb = OneMb * 1024; const long OneTb = OneGb * 1024; double returnValue; string suffix = string.Empty; if (bytesString.IndexOf(" ") > 0) { returnValue = float.Parse(bytesString.Substring(0, bytesString.IndexOf(" "))); suffix = bytesString.Substring(bytesString.IndexOf(" ") + 1).ToUpperInvariant(); } else { returnValue = float.Parse(bytesString.Substring(0, bytesString.Length - 2)); suffix = bytesString.ToUpperInvariant().Substring(bytesString.Length - 2); } switch (suffix) { case "KB": { returnValue *= OneKb; break; } case "MB": { returnValue *= OneMb; break; } case "GB": { returnValue *= OneGb; break; } case "TB": { returnValue *= OneTb; break; } default: { break; } } return Convert.ToInt64(returnValue); } 

Basado en la elegante solución de NeverHopeless:

 private static readonly KeyValuePair[] Thresholds = { // new KeyValuePair(0, " Bytes"), // Don't devide by Zero! new KeyValuePair(1, " Byte"), new KeyValuePair(2, " Bytes"), new KeyValuePair(1024, " KB"), new KeyValuePair(1048576, " MB"), // Note: 1024 ^ 2 = 1026 (xor operator) new KeyValuePair(1073741824, " GB"), new KeyValuePair(1099511627776, " TB"), new KeyValuePair(1125899906842620, " PB"), new KeyValuePair(1152921504606850000, " EB"), // These don't fit into a int64 // new KeyValuePair(1180591620717410000000, " ZB"), // new KeyValuePair(1208925819614630000000000, " YB") }; ///  /// Returns x Bytes, kB, Mb, etc... ///  public static string ToByteSize(this long value) { if (value == 0) return "0 Bytes"; // zero is plural for (int t = Thresholds.Length - 1; t > 0; t--) if (value >= Thresholds[t].Key) return ((double)value / Thresholds[t].Key).ToString("0.00") + Thresholds[t].Value; return "-" + ToByteSize(-value); // negative bytes (common case optimised to the end of this routine) } 

Tal vez hay comentarios excesivos, pero tiendo a dejarlos para evitar cometer los mismos errores en futuras visitas …

No.

Pero puedes implementar esto;

  static double ConvertBytesToMegabytes(long bytes) { return (bytes / 1024f) / 1024f; } static double ConvertKilobytesToMegabytes(long kilobytes) { return kilobytes / 1024f; } 

Consulte también Cómo convertir correctamente el tamaño del archivo en bytes en mega o gigabytes.

Qué tal si:

 public void printMB(uint sizekB) { double sizeMB = (double) sizekB / 1024; Console.WriteLine("Size is " + sizeMB.ToString("0.00") + "MB"); } 

Ej. Llamar como

 printMB(123456); 

Producirá resultados

 "Size is 120,56 MB" 

Fui por la solución JerKimballs, y los pulgares arriba a eso. Sin embargo, me gustaría agregar / señalar que esto es realmente una cuestión de controversia en su conjunto. En mi investigación (por otras razones) he encontrado la siguiente información.

Cuando las personas normales (he oído que existen) hablan de gigabytes, se refieren al sistema métrico donde 1000 a la potencia de 3 a partir del número original de bytes == la cantidad de gigabytes. Sin embargo, por supuesto están los estándares IEC / JEDEC que se resumen muy bien en wikipedia, que en lugar de 1000 a la potencia de x tienen 1024. Lo cual para dispositivos físicos de almacenamiento (y supongo lógico como amazon y otros) significa un una diferencia cada vez mayor entre métrica vs IEC. Entonces, por ejemplo, 1 TB == 1 terabyte métrico es 1000 a la potencia de 4, pero IEC oficialmente llama el número similar a 1 TiB, tebibyte como 1024 a la potencia de 4. Pero, por desgracia, en aplicaciones no técnicas (lo haría ir por audiencia) la norma es la métrica, y en mi propia aplicación para uso interno actualmente explico la diferencia en la documentación. Pero para fines de exhibición, no ofrezco nada más que métricas. Internamente, aunque no es relevante en mi aplicación, solo almaceno los bytes y realizo el cálculo para la visualización.

Como nota al margen, me parece un tanto deslucido que el .NET framework AFAIK (y frecuentemente me equivoco, gracias a los poderes fácticos) incluso en su versión 4.5 no contiene nada sobre esto en ninguna biblioteca internamente. Uno esperaría que una biblioteca de código abierto de algún tipo fuera NuGettable en algún momento, pero admito que esto es un pequeño problema. Por otro lado System.IO.DriveInfo y otros también solo tienen bytes (tan largos) que es bastante claro.

https://github.com/logary/logary/blob/master/src/Logary/DataModel.fs#L832-L837

 let scaleBytes (value : float) : float * string = let log2 x = log x / log 2. let prefixes = [| ""; "Ki"; "Mi"; "Gi"; "Ti"; "Pi" |] // note the capital K and the 'i' let index = int (log2 value) / 10 1. / 2.**(float index * 10.), sprintf "%s%s" prefixes.[index] (Units.symbol Bytes) 
 public static class MyExtension { public static string ToPrettySize(this float Size) { return ConvertToPrettySize(Size, 0); } public static string ToPrettySize(this int Size) { return ConvertToPrettySize(Size, 0); } private static string ConvertToPrettySize(float Size, int R) { float F = Size / 1024f; if (F < 1) { switch (R) { case 0: return string.Format("{0:0.00} byte", Size); case 1: return string.Format("{0:0.00} kb", Size); case 2: return string.Format("{0:0.00} mb", Size); case 3: return string.Format("{0:0.00} gb", Size); } } return ConvertToPrettySize(F, ++R); } } 

¿Qué tal una recursión?

 private static string ReturnSize(double size, string sizeLabel) { if (size > 1024) { if (sizeLabel.Length == 0) return ReturnSize(size / 1024, "KB"); else if (sizeLabel == "KB") return ReturnSize(size / 1024, "MB"); else if (sizeLabel == "MB") return ReturnSize(size / 1024, "GB"); else if (sizeLabel == "GB") return ReturnSize(size / 1024, "TB"); else return ReturnSize(size / 1024, "PB"); } else { if (sizeLabel.Length > 0) return string.Concat(size.ToString("0.00"), sizeLabel); else return string.Concat(size.ToString("0.00"), "Bytes"); } } 

Entonces puedes llamarlo:

 ReturnSize(size, string.Empty); 

Como se publicó anteriormente, la recursividad es la forma favorita, con la ayuda del logaritmo.

La siguiente función tiene 3 argumentos: la entrada, la restricción de dimensión de la salida, que es el tercer argumento.

 int ByteReDim(unsigned long ival, int constraint, unsigned long *oval) { int base = 1 + (int) log10(ival); (*oval) = ival; if (base > constraint) { (*oval) = (*oval) >> 10; return(1 + ByteReDim((*oval), constraint, oval)); } else return(0); } 

Ahora vamos a convertir 12GB de RAM en varias unidades:

 int main(void) { unsigned long RAM; int unit; // index of below symbols array char symbol[5] = {'B', 'K', 'M', 'G', 'T'}; unit = ByteReDim(12884901888, 12, &RAM); printf("%lu%c\n", RAM, symbol[unit]); // output is 12884901888B unit = ByteReDim(12884901888, 9, &RAM); printf("%lu%c\n", RAM, symbol[unit]); // output is 12582912K unit = ByteReDim(12884901888, 6, &RAM); printf("%lu%c\n", RAM, symbol[unit]); // output is 12288M unit = ByteReDim(12884901888, 3, &RAM); printf("%lu%c\n", RAM, symbol[unit]); // output is 12G } 

La respuesta de @Servy fue agradable y sucinta. Creo que puede ser aún más simple?

 private static string[] suffixes = new [] { " B", " KB", " MB", " GB", " TB", " PB" }; public static string ToSize(double number, int precision = 2) { // unit's number of bytes const double unit = 1024; // suffix counter int i = 0; // as long as we're bigger than a unit, keep going while(number > unit) { number /= unit; i++; } // apply precision and current suffix return Math.Round(number, precision) + suffixes[i]; } 

Lo uso para Windows (prefijos binarios):

 static readonly string[] BinaryPrefix = { "bytes", "KB", "MB", "GB", "TB" }; // , "PB", "EB", "ZB", "YB" string GetMemoryString(double bytes) { int counter = 0; double value = bytes; string text = ""; do { text = value.ToString("0.0") + " " + BinaryPrefix[counter]; value /= 1024; counter++; } while (Math.Floor(value) > 0 && counter < BinaryPrefix.Length); return text; }