Функция Delphi для отображения количества байтов, как это делает Windows

Это простой (я думаю).

есть ли встроенная функция системы или функция, созданная кем-то, которая может быть вызвана из Delphi, которая будет отображать количество байтов (например, размер файла), как Windows отображается в окне свойств файла?

например, вот как окно свойств Windows отображает различные размеры:

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

дисплей умный об использовании байтов, КБ, Мб или ГБ, и показывает только 3 значащие цифры для КБ, МБ и ГБ. Затем следует, что, отображая точное количество байтов в скобках с запятыми, разделяющими тысячи. Это очень хороший дисплей, хорошо продуманный.

кто-нибудь знает такой функции?


Edit: я очень удивлен, что для этого не было функции.

Спасибо за ваши полезные идеи. Я придумал это, что, кажется, работает:

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;

это, вероятно, достаточно хорошо, но есть ли что-нибудь лучше?

3 ответов


см. следующие функции, все в shlwapi библиотека.

любой из них даст вам первую порцию желаемого формат отображения. Проверьте документацию или напишите свои собственные тесты, чтобы подтвердить, что они дают ожидаемые преобразования относительно того, состоит ли мегабайт из 1000 или 1024 килобайт. Для второй части формата отображения вы можете начать с ответов на другой вопрос переполнения стека:

но, возможно, что вопрос-неправильный путь, чтобы спуститься, так как все предложения там, а также FloatToStrF, сбой в верхних пределах Int64. Вы потеряете несколько байтов, но я считаю эти довольно важные байты, так как цель второго значения в этом формате отображения-предоставить точное число.

как только у вас есть все части, склейте их вместе. Я использую гипотетический IntToStrCommas функция здесь, и если вы хотите реализовать это как FloatToStrF, идти вперед.

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;

не совсем то, что вам нужно, но у меня есть функция в моей библиотеке, которая может дать вам представление о том, как справиться с этим:

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;

Это из моего блока 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;