Esta no es la forma más eficiente de hacerlo, pero es más fácil de leer si no está familiarizado con las matemáticas de registro, y debe ser lo suficientemente rápido para la mayoría de los escenarios.
string[] sizes ={"B","KB","MB","GB","TB"};double len =newFileInfo(filename).Length;int order =0;while(len >=1024&& order < sizes.Length-1){
order++;
len = len/1024;}// Adjust the format string to your preferences. For example "{0:0.#}{1}" would// show a single decimal place, and no space.string result =String.Format("{0:0.##} {1}", len, sizes[order]);
@Constantin bien eso depende del sistema operativo? Windows todavía cuenta 1024 bytes como 1 KB y 1 MB = 1024 KB, personalmente quiero tirar el KiB por la ventana y solo contar cada cosa usando 1024? ...
Peter
44
@Petoj no depende del sistema operativo, la definición es independiente del sistema operativo. De Wikipedia:The unit was established by the International Electrotechnical Commission (IEC) in 1998 and has been accepted for use by all major standards organizations
ANeves
3
Prefiero este código, ya que parece ejecutarse más rápido, pero lo modifiqué ligeramente para permitir diferentes números de decimales. Los números más pequeños muestran mejor 2 lugares decimales, por ejemplo, 1,38 MB, mientras que los números más grandes requieren menos decimales, por ejemplo, 246k o 23.5KB:
Myke Black
321
usando Log para resolver el problema ...
staticStringBytesToString(long byteCount){string[] suf ={"B","KB","MB","GB","TB","PB","EB"};//Longs run out around EBif(byteCount ==0)return"0"+ suf[0];long bytes =Math.Abs(byteCount);int place =Convert.ToInt32(Math.Floor(Math.Log(bytes,1024)));double num =Math.Round(bytes /Math.Pow(1024, place),1);return(Math.Sign(byteCount)* num).ToString()+ suf[place];}
También en c #, pero debería ser fácil de convertir. También redondeé a 1 decimal para facilitar la lectura.
Básicamente, determine el número de lugares decimales en Base 1024 y luego divídalo entre 1024 ^ decimales.
Y algunas muestras de uso y salida:
Console.WriteLine(BytesToString(9223372036854775807));//Results in 8EBConsole.WriteLine(BytesToString(0));//Results in 0BConsole.WriteLine(BytesToString(1024));//Results in 1KBConsole.WriteLine(BytesToString(2000000));//Results in 1.9MBConsole.WriteLine(BytesToString(-9023372036854775807));//Results in -7.8EB
Editar: Se señaló que me perdí un piso de matemáticas, así que lo incorporé. (Convert.ToInt32 usa redondeo, no truncamiento y es por eso que Floor es necesario). Gracias por la captura.
Edit2: Hubo un par de comentarios sobre tamaños negativos y tamaños de 0 bytes, así que actualicé para manejar esos 2 casos.
Quiero advertir que si bien esta respuesta es de hecho un código corto, no es la más optimizada. Me gustaría que eche un vistazo al método publicado por @humbads. Ejecuté microtesting enviando 10 000 000 de tamaños de archivos generados aleatoriamente a través de ambos métodos y esto arroja números de que su método es ~ 30% más rápido. Sin embargo, hice un poco más de limpieza de su método (asignaciones y casting de unnesecary). Además, ejecuté una prueba con un tamaño negativo (cuando está comparando archivos), mientras que el método de humbads procesa sin problemas este método de registro arrojará una excepción.
IvanL
1
Sí, debe agregar Math.Abs para tamaños negativos. Además, el código no maneja el caso si el tamaño es exactamente 0.
dasheddot
Math.Abs, Math.Floor, Math.Log, Convertir a entero, Math.Round, Math.Pow, Math.Sign, Agregar, Multiplicar, Dividir? ¿No eran toneladas de matemáticas solo un gran aumento en el procesador? Esto es probablemente más lento que el código @humbads
Jayson Ragasa
Falla para double.MaxValue(lugar = 102)
BrunoLM
¡Funciona genial! Para imitar la forma en que funciona Windows (al menos en mi Windows 7 ultimate), reemplace Math.Round con Math.Ceiling. Gracias de nuevo. Me gusta esta solución
H_He
101
Aquí se publica una versión probada y significativamente optimizada de la función solicitada:
+1! Más simple y directo! ¡Hace que el procesador haga los cálculos de manera fácil y rápida!
Jayson Ragasa
Para su información, no utiliza el valor en double readable = (i < 0 ? -i : i);ningún lugar, así que elimínelo. Una cosa más, el elenco es redaundat
Royi Namir
Eliminé el elenco, agregué comentarios y solucioné un problema con el signo negativo.
humbads
Gran respuesta. Gracias, ¿por qué no solo usar Math.Abs?
kspearrin
1
(i <0? -i: i) es aproximadamente un 15% más rápido que Math.Abs. Para un millón de llamadas, Math.Abs es 0.5 milisegundos más lento en mi máquina: 3.2 ms frente a 3.7 ms.
humbads
72
[DllImport("Shlwapi.dll",CharSet=CharSet.Auto)]publicstaticexternlongStrFormatByteSize(long fileSize
,[MarshalAs(UnmanagedType.LPTStr)]StringBuilder buffer
,int bufferSize );/// <summary>/// Converts a numeric value into a string that represents the number expressed as a size value in bytes, kilobytes, megabytes, or gigabytes, depending on the size./// </summary>/// <param name="filelength">The numeric value to be converted.</param>/// <returns>the converted string</returns>publicstaticstringStrFormatByteSize(long filesize){StringBuilder sb =newStringBuilder(11);StrFormatByteSize( filesize, sb, sb.Capacity);return sb.ToString();}
Puede que sea un novato, pero usar un cañón gigante como pinvoke para matar a ese pato es un gran mal uso.
Bart
27
¿Es esto lo que usa el explorador? Si es así, entonces magníficamente útil para permitir que las personas coincidan con el tamaño de archivo que les muestra con lo que muestra el explorador.
Andrew Backer
8
Y uno que no reinventa la rueda
Matthew Lock
¿No son 11 caracteres un límite constante y un poco bajo para eso? Quiero decir, otros idiomas pueden usar más caracteres para el acrónimo de tamaño de byte u otros estilos de formato.
Ray
1
@Bart, a los novatos les toma un tiempo aprender la sabiduría en esto: "Debemos olvidarnos de las pequeñas eficiencias, digamos alrededor del 97% del tiempo: la optimización prematura es la raíz de todo mal" ubiquity.acm.org/article.cfm? id = 1513451
Matthew Lock
22
Una forma más de pelarlo, sin ningún tipo de bucles y con soporte de tamaño negativo (tiene sentido para cosas como deltas de tamaño de archivo):
Buena respuesta. Debería haber un problema cuando el tamaño del archivo es demasiado pequeño, en cuyo caso / 1024 devuelve 0. Podría usar un tipo fraccionario y llamar Math.Ceilingo algo así.
nawfal
10
Aquí hay una respuesta concisa que determina la unidad automáticamente.
para todos los que se preguntan por qué hay un oKMGTPE posterior: es francés ( byteestá octeten francés). Para cualquier otro idioma, simplemente reemplace el oconb
Debe verificar: while (size> = 1024 && s <suffixes.Length).
TcKs
no ... un entero con signo de 64 bits no puede ir más allá del ZB ... que representa los números 2 ^ 70.
bobwienholt
77
Entonces, ¿por qué poner en YB?
Configurador
A mí me gusta más esta respuesta, pero todos aquí pusieron soluciones realmente ineficientes, debería usar "shift = size >> 10" shift es mucho más rápido que la división ... y creo que es bueno tener el hay un especificador griego adicional, porque en el futuro cercano, una función DLR posible no necesitaría el "tamaño largo ..." podría estar en una CPU de vector de 128 bits o algo que pueda contener ZB y más grande;)
RandomNickName42
44
Bitshifting fue más eficiente que la división en los días de la codificación C en el metal. ¿Has hecho una prueba de rendimiento en .NET para ver si el bithift realmente es más eficiente? No hace mucho tiempo, miré el estado del intercambio xor y descubrí que en realidad era más lento en .NET en comparación con el uso de una variable temporal.
Pete
7
Si intenta hacer coincidir el tamaño como se muestra en la vista de detalles del Explorador de Windows, este es el código que desea:
Esto no solo coincidirá exactamente con el Explorador, sino que también proporcionará las cadenas traducidas para usted y coincidirá con las diferencias en las versiones de Windows (por ejemplo, en Win10, K = 1000 frente a las versiones anteriores K = 1024).
Este código no se compila, debe especificar dll de qué función proviene. Entonces, el prototipo de la función completa suena así: [DllImport ("shlwapi.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern long StrFormatKBSize (long qdw, [MarshalAs (UnmanagedType.LPTStr)] StringBuilder pszBuf, int cchBuf ); Déjame ser el primero en favorecer esta solución. ¿Por qué reinventar la rueda si la rueda ya se inventó? Este es el enfoque típico de todos los programadores de C #, pero desafortunadamente C # no alcanza todos los objetivos que alcanza C ++.
TarmoPikaro
Y una corrección de error más: Int64.MaxValue alcanza 9,223,372,036,854,775,807, lo que requiere asignar un tamaño de búfer de 25+: lo he redondeado a 32 por si acaso (no 11 como en el código de demostración anterior).
TarmoPikaro
Gracias @TarmoPikaro. Cuando copié de mi código de trabajo, perdí el DllImport. También aumentó el tamaño del búfer según su recomendación. ¡Buena atrapada!
Metalogic
enfoque impresionante
tbhaxor
Esto muestra solo la unidad KB. La idea es mostrar la unidad más grande según el valor.
jstuardo
5
Mezcla de todas las soluciones :-)
/// <summary>/// Converts a numeric value into a string that represents the number expressed as a size value in bytes,/// kilobytes, megabytes, or gigabytes, depending on the size./// </summary>/// <param name="fileSize">The numeric value to be converted.</param>/// <returns>The converted string.</returns>publicstaticstringFormatByteSize(double fileSize){FileSizeUnit unit =FileSizeUnit.B;while(fileSize >=1024&& unit <FileSizeUnit.YB){
fileSize = fileSize /1024;
unit++;}returnstring.Format("{0:0.##} {1}", fileSize, unit);}/// <summary>/// Converts a numeric value into a string that represents the number expressed as a size value in bytes,/// kilobytes, megabytes, or gigabytes, depending on the size./// </summary>/// <param name="fileInfo"></param>/// <returns>The converted string.</returns>publicstaticstringFormatByteSize(FileInfo fileInfo){returnFormatByteSize(fileInfo.Length);}}publicenumFileSizeUnit:byte{
B,
KB,
MB,
GB,
TB,
PB,
EB,
ZB,
YB
}
Como la solución de @ NET3. Use shift en lugar de division para probar el rango de bytes, porque la división requiere más costo de CPU.
privatestaticreadonlystring[] UNITS =newstring[]{"B","KB","MB","GB","TB","PB","EB"};publicstaticstringFormatSize(ulong bytes){int c =0;for(c =0; c < UNITS.Length; c++){ulong m =(ulong)1<<((c +1)*10);if(bytes < m)break;}double n = bytes /(double)((ulong)1<<(c *10));returnstring.Format("{0:0.##} {1}", n, UNITS[c]);}
Dado que estas funciones son para fines de presentación, uno debe proporcionar una cultura, por ejemplo: string.Format(CultureInfo.CurrentCulture, "{0:0.##} {1}", fileSize, unit);
Dependiendo del contexto, un kilobyte puede tener 1000 o 1024 bytes . Lo mismo ocurre con MB, GB, etc.
Un kilobyte significa 1000 bytes ( wolframalpha.com/input/?i=kilobyte ), no depende del contexto. Es históricamente dependía de contexto, como dice Wikipedia, y era de jure cambió en 1998 y el cambio de facto comenzó alrededor de 2005, cuando terabyte discos duros trajeron a la atención del público. El término para 1024 bytes es kibibyte. El código que los cambia según la cultura está produciendo información incorrecta.
Superbest
1
Un enfoque más, por lo que vale. Me gustó la solución optimizada @humbads mencionada anteriormente, así que he copiado el principio, pero lo he implementado de manera un poco diferente.
Supongo que es discutible si debería ser un método de extensión (ya que no todos los largos son necesariamente tamaños de bytes), pero me gustan, ¡y es en algún lugar donde puedo encontrar el método la próxima vez que lo necesite!
Con respecto a las unidades, no creo que haya dicho nunca 'Kibibyte' o 'Mebibyte' en mi vida, y aunque soy escéptico de tales estándares forzados en lugar de evolucionados, supongo que evitará la confusión a largo plazo .
publicstaticclassLongExtensions{privatestaticreadonlylong[] numberOfBytesInUnit;privatestaticreadonlyFunc<long,string>[] bytesToUnitConverters;staticLongExtensions(){
numberOfBytesInUnit =newlong[6]{1L<<10,// Bytes in a Kibibyte1L<<20,// Bytes in a Mebibyte1L<<30,// Bytes in a Gibibyte1L<<40,// Bytes in a Tebibyte1L<<50,// Bytes in a Pebibyte1L<<60// Bytes in a Exbibyte};// Shift the long (integer) down to 1024 times its number of units, convert to a double (real number), // then divide to get the final number of units (units will be in the range 1 to 1023.999)Func<long,int,string>FormatAsProportionOfUnit=(bytes, shift)=>(((double)(bytes >> shift))/1024).ToString("0.###");
bytesToUnitConverters =newFunc<long,string>[7]{
bytes => bytes.ToString()+" B",
bytes =>FormatAsProportionOfUnit(bytes,0)+" KiB",
bytes =>FormatAsProportionOfUnit(bytes,10)+" MiB",
bytes =>FormatAsProportionOfUnit(bytes,20)+" GiB",
bytes =>FormatAsProportionOfUnit(bytes,30)+" TiB",
bytes =>FormatAsProportionOfUnit(bytes,40)+" PiB",
bytes =>FormatAsProportionOfUnit(bytes,50)+" EiB",};}publicstaticstringToReadableByteSizeString(thislong bytes){if(bytes <0)return"-"+Math.Abs(bytes).ToReadableByteSizeString();int counter =0;while(counter < numberOfBytesInUnit.Length){if(bytes < numberOfBytesInUnit[counter])return bytesToUnitConverters[counter](bytes);
counter++;}return bytesToUnitConverters[counter](bytes);}}
Utilizo el método de extensión larga a continuación para convertir a una cadena de tamaño legible por humanos. Este método es la implementación en C # de la solución Java de esta misma pregunta publicada en Stack Overflow, aquí .
/// <summary>/// Convert a byte count into a human readable size string./// </summary>/// <param name="bytes">The byte count.</param>/// <param name="si">Whether or not to use SI units.</param>/// <returns>A human readable size string.</returns>publicstaticstringToHumanReadableByteCount(thislong bytes
,bool si
){var unit = si
?1000:1024;if(bytes < unit){return $"{bytes} B";}var exp =(int)(Math.Log(bytes)/Math.Log(unit));return $"{bytes / Math.Pow(unit, exp):F2} "+
$"{(si ? "kMGTPE" : "KMGTPE")[exp - 1] + (si ? string.Empty : "i")}B";}
Respuestas:
Esta no es la forma más eficiente de hacerlo, pero es más fácil de leer si no está familiarizado con las matemáticas de registro, y debe ser lo suficientemente rápido para la mayoría de los escenarios.
fuente
The unit was established by the International Electrotechnical Commission (IEC) in 1998 and has been accepted for use by all major standards organizations
usando Log para resolver el problema ...
También en c #, pero debería ser fácil de convertir. También redondeé a 1 decimal para facilitar la lectura.
Básicamente, determine el número de lugares decimales en Base 1024 y luego divídalo entre 1024 ^ decimales.
Y algunas muestras de uso y salida:
Editar: Se señaló que me perdí un piso de matemáticas, así que lo incorporé. (Convert.ToInt32 usa redondeo, no truncamiento y es por eso que Floor es necesario). Gracias por la captura.
Edit2: Hubo un par de comentarios sobre tamaños negativos y tamaños de 0 bytes, así que actualicé para manejar esos 2 casos.
fuente
double.MaxValue
(lugar = 102)Aquí se publica una versión probada y significativamente optimizada de la función solicitada:
Tamaño de archivo legible para humanos de C #: función optimizada
Código fuente:
fuente
double readable = (i < 0 ? -i : i);
ningún lugar, así que elimínelo. Una cosa más, el elenco es redaundatMath.Abs
?De: http://www.pinvoke.net/default.aspx/shlwapi/StrFormatByteSize.html
fuente
Una forma más de pelarlo, sin ningún tipo de bucles y con soporte de tamaño negativo (tiene sentido para cosas como deltas de tamaño de archivo):
Y aquí está el conjunto de pruebas:
fuente
Partida de los ByteSize biblioteca. ¡Es
System.TimeSpan
para los bytes!Maneja la conversión y el formato por usted.
También hace representación de cadenas y análisis.
fuente
Me gusta usar el siguiente método (admite hasta terabytes, que es suficiente para la mayoría de los casos, pero se puede extender fácilmente):
Tenga en cuenta que esto está escrito para C # 6.0 (2015), por lo que podría necesitar un poco de edición para versiones anteriores.
fuente
fuente
Math.Ceiling
o algo así.Aquí hay una respuesta concisa que determina la unidad automáticamente.
"b" es para bit, "B" es para Byte y "KMGTPEZY" son respectivamente para kilo, mega, giga, tera, peta, exa, zetta y yotta
Se puede ampliar para tener en cuenta ISO / IEC80000 :
fuente
o
KMGTPE posterior: es francés (byte
estáoctet
en francés). Para cualquier otro idioma, simplemente reemplace elo
conb
fuente
Si intenta hacer coincidir el tamaño como se muestra en la vista de detalles del Explorador de Windows, este es el código que desea:
Esto no solo coincidirá exactamente con el Explorador, sino que también proporcionará las cadenas traducidas para usted y coincidirá con las diferencias en las versiones de Windows (por ejemplo, en Win10, K = 1000 frente a las versiones anteriores K = 1024).
fuente
Mezcla de todas las soluciones :-)
fuente
Hay un proyecto de código abierto que puede hacer eso y mucho más.
http://humanizr.net/#bytesize
https://github.com/MehdiK/Humanizer
fuente
Como la solución de @ NET3. Use shift en lugar de division para probar el rango de
bytes
, porque la división requiere más costo de CPU.fuente
¿Supongo que está buscando "1.4 MB" en lugar de "1468006 bytes"?
No creo que haya una forma integrada de hacerlo en .NET. Tendrá que averiguar qué unidad es apropiada y formatearla.
Editar: Aquí hay un código de muestra para hacer exactamente eso:
http://www.codeproject.com/KB/cpp/formatsize.aspx
fuente
¿Qué tal algo de recursión:
Entonces lo llamas:
fuente
Mis 2 centavos:
string.Format(CultureInfo.CurrentCulture, "{0:0.##} {1}", fileSize, unit);
fuente
Un enfoque más, por lo que vale. Me gustó la solución optimizada @humbads mencionada anteriormente, así que he copiado el principio, pero lo he implementado de manera un poco diferente.
Supongo que es discutible si debería ser un método de extensión (ya que no todos los largos son necesariamente tamaños de bytes), pero me gustan, ¡y es en algún lugar donde puedo encontrar el método la próxima vez que lo necesite!
Con respecto a las unidades, no creo que haya dicho nunca 'Kibibyte' o 'Mebibyte' en mi vida, y aunque soy escéptico de tales estándares forzados en lugar de evolucionados, supongo que evitará la confusión a largo plazo .
fuente
Utilizo el método de extensión larga a continuación para convertir a una cadena de tamaño legible por humanos. Este método es la implementación en C # de la solución Java de esta misma pregunta publicada en Stack Overflow, aquí .
fuente