Функция 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 библиотека.
-
StrFormatByteSizeA
(параметр DWord) -
StrFormatByteSizeW
(параметр Int64) -
StrFormatByteSize64
(в режиме Unicode это действительноStrFormatByteSizeW
) -
StrFormatByteSizeEx
(Vista SP2; может управлять округлением)
любой из них даст вам первую порцию желаемого формат отображения. Проверьте документацию или напишите свои собственные тесты, чтобы подтвердить, что они дают ожидаемые преобразования относительно того, состоит ли мегабайт из 1000 или 1024 килобайт. Для второй части формата отображения вы можете начать с ответов на другой вопрос переполнения стека:
- как конвертировать int в валюте? (он действительно спрашивал, как вставить запятые, а не конкретно о деньгах.)
но, возможно, что вопрос-неправильный путь, чтобы спуститься, так как все предложения там, а также 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;