2009-08-17 15 views
6

Este es uno simple (creo).Función Delphi para mostrar el número de bytes como Windows

¿Hay un sistema incorporado en la función, o una función que alguien ha creado que se puede llamar desde Delphi, que mostrará una cantidad de bytes (por ejemplo, un tamaño de archivo), como muestra Windows en el cuadro de propiedades de un archivo?

p. Ej. Así es como cuadro de propiedades de Windows muestra diversos tamaños:

539 bytes (539 bytes) 
35.1 KB (35,974 bytes) 
317 MB (332,531,365 bytes) 
2.07 GB (2,224,617,077 bytes) 

La pantalla es inteligente acerca del uso de bytes, KB, MB o GB, y muestra sólo 3 dígitos significativos para el KB, MB y GB. Luego se deduce que al mostrar el número exacto de bytes entre paréntesis con comas que separan los miles. Es una pantalla muy bonita, bien pensada.

¿Alguien conoce esta función?


Editar: Estoy muy sorprendido de que no haya una función para esto.

Gracias por sus ideas útiles. He llegado a esto, que parece funcionar:

function BytesToDisplay(A:int64): string; 
var 
    A1, A2, A3: double; 
begin 
    A1 := A/1024; 
    A2 := A1/1024; 
    A3 := A2/1024; 
    if A1 < 1 then Result := floattostrf(A, ffNumber, 15, 0) + ' bytes' 
    else if A1 < 10 then Result := floattostrf(A1, ffNumber, 15, 2) + ' KB' 
    else if A1 < 100 then Result := floattostrf(A1, ffNumber, 15, 1) + ' KB' 
    else if A2 < 1 then Result := floattostrf(A1, ffNumber, 15, 0) + ' KB' 
    else if A2 < 10 then Result := floattostrf(A2, ffNumber, 15, 2) + ' MB' 
    else if A2 < 100 then Result := floattostrf(A2, ffNumber, 15, 1) + ' MB' 
    else if A3 < 1 then Result := floattostrf(A2, ffNumber, 15, 0) + ' MB' 
    else if A3 < 10 then Result := floattostrf(A3, ffNumber, 15, 2) + ' GB' 
    else if A3 < 100 then Result := floattostrf(A3, ffNumber, 15, 1) + ' GB' 
    else Result := floattostrf(A3, ffNumber, 15, 0) + ' GB'; 
    Result := Result + ' (' + floattostrf(A, ffNumber, 15, 0) + ' bytes)'; 
end; 

Esto es probablemente lo suficientemente bueno, pero ¿hay algo mejor?

Respuesta

12

Consulte las siguientes funciones, todos en el shlwapi library.

Cualquiera de ellos le dará la primera parte del formato de visualización que desee. Consulte la documentación o escriba sus propias pruebas para confirmar que dan las conversiones que espera con respecto a si un megabyte consiste en 1000 o 1024 kilobytes. Para la segunda parte de su formato de visualización, se puede comenzar con las respuestas a otra pregunta de desbordamiento de pila: (. Él en realidad preguntaba cómo insertar comas, no específicamente sobre el dinero)

Pero tal vez esa pregunta es la vía incorrecta para bajar ya que todas las sugerencias allí, así como FloatToStrF, fallan en los límites superiores de Int64. Perderá algunos bytes, pero considero esos bytes bastante importantes ya que el propósito del segundo valor en ese formato de visualización es proporcionar un número exacto.

Una vez que tenga todas las piezas, péguelas. Estoy usando una función hipotética IntToStrCommas aquí, y si quiere implementar eso como FloatToStrF, adelante.

function BytesToDisplay(const num: Int64): string; 
var 
    // If GB is the largest unit available, then 20 characters is 
    // enough for "17,179,869,183.99 GB", which is MaxUInt64. 
    buf: array[0..20] of Char; 
begin 
    if StrFormatByteSize64(num, buf, Length(buf)) = nil then 
    raise EConvertError.CreateFmt('Error converting %d', [num]); 
    Result := Format('%s (%s bytes)', [buf, IntToStrCommas(num)]); 
end; 
+1

StrFormatByteSize64 parece ser lo que Windows usa para la primera parte. Pero llamar a esa función desde Delphi requiere configurar un búfer, no es bonito. Para la segunda parte, floattostrf parece funcionar mejor que las soluciones en su enlace. – lkessler

+0

como usted tiene alguna idea de cuánto tiempo puede ser la salida, utilice una matriz empaquetada [1..n] de char para el búfer. Pase @CharArray [1] como el puntero. –

+0

Excelente consejo! (StrFormatByteSizeW) –

5

No es exactamente lo que está buscando, pero tengo una función en mi biblioteca que puede dar una idea de cómo hacer frente a esta:

function FormatByteSize(const bytes: Longword): string; 
var 
    B: byte; 
    KB: word; 
    MB: Longword; 
    GB: Longword; 
    TB: UInt64; 
begin 

    B := 1; //byte 
    KB := 1024 * B; //kilobyte 
    MB := 1000 * KB; //megabyte 
    GB := 1000 * MB; //gigabyte 
    TB := 1000 * GB; //teraabyte 

    if bytes > TB then 
    result := FormatFloat('#.## TB', bytes/TB) 
    else 
    if bytes > GB then 
     result := FormatFloat('#.## GB', bytes/GB) 
    else 
     if bytes > MB then 
     result := FormatFloat('#.## MB', bytes/MB) 
     else 
     if bytes > KB then 
      result := FormatFloat('#.## KB', bytes/KB) 
     else 
      result := FormatFloat('#.## bytes', bytes) ; 
end; 
+3

¿No deberían los demás de 1000 también ser de 1024? Pero bastante conciso. – lkessler

+0

Sí, técnicamente debería ser 1024x1024x ... pero esto fue escrito hace un tiempo para un Servidor de Video específico. Publicado como ejemplo simple – Gerard

+0

Si divide por 1024, también debe utilizar las unidades estándar ISO TiB, GiB, MiB y KiB. – dummzeuch

0

Esto es de mi unidad de dzlib u_dzConvertUtils:

/// these contants refer to the "Xx binary byte" units as defined by the 
/// International Electronical Commission (IEC) and endorsed by the 
/// IEE and CiPM </summary> 
const 
    OneKibiByte = Int64(1024); 
    OneMebiByte = Int64(1024) * OneKibiByte; 
    OneGibiByte = Int64(1024) * OneMebiByte; 
    OneTebiByte = Int64(1024) * OneGibiByte; 
    OnePebiByte = Int64(1024) * OneTebiByte; 
    OneExbiByte = Int64(1024) * OnePebiByte; 

/// <summary> 
/// Converts a file size to a human readable string, e.g. 536870912000 = 5.00 GiB (gibibyte) </summary> 
function FileSizeToHumanReadableString(_FileSize: Int64): string; 
begin 
    if _FileSize > 5 * OneExbiByte then 
    Result := Format(_('%.2f EiB'), [_FileSize/OneExbiByte]) 
    else if _FileSize > 5 * OnePebiByte then 
    Result := Format(_('%.2f PiB'), [_FileSize/OnePebiByte]) 
    else if _FileSize > 5 * OneTebiByte then 
    Result := Format(_('%.2f TiB'), [_FileSize/OneTebiByte]) 
    else if _FileSize > 5 * OneGibiByte then 
    Result := Format(_('%.2f GiB'), [_FileSize/OneGibiByte]) 
    else if _FileSize > 5 * OneMebiByte then 
    Result := Format(_('%.2f MiB'), [_FileSize/OneMebiByte]) 
    else if _FileSize > 5 * OneKibiByte then 
    Result := Format(_('%.2f KiB'), [_FileSize/OneKibiByte]) 
    else 
    Result := Format(_('%d Bytes'), [_FileSize]); 
end; 
Cuestiones relacionadas