像 Windows 一样显示字节数的 Delphi 函数

Posted

技术标签:

【中文标题】像 Windows 一样显示字节数的 Delphi 函数【英文标题】:Delphi Function to Display Number of Bytes as Windows Does 【发布时间】:2009-08-17 02:55:21 【问题描述】:

这是一个简单的(我认为)。

是否有系统内置函数或某人创建的可从 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)

显示器可以巧妙地使用字节、KB、MB 或 GB,并且只显示 KB、MB 和 GB 的 3 个有效数字。然后,通过在括号中显示确切的字节数,用逗号分隔千位。这是一个非常好的展示,经过深思熟虑。

有人知道这样的功能吗?


编辑:我很惊讶没有这个功能。

感谢您提供有用的想法。我想出了这个,这似乎可行:

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;

这可能已经足够了,但还有什么更好的吗?

【问题讨论】:

【参考方案1】:

查看以下函数,全部在shlwapi library中。

StrFormatByteSizeA(双字参数) StrFormatByteSizeW(Int64 参数) StrFormatByteSize64(在Unicode模式下,真的是StrFormatByteSizeWStrFormatByteSizeEx(Vista SP2;可以控制舍入)

其中任何一个都会为您提供所需显示格式的第一部分。检查文档或编写您自己的测试,以确认它们给出了您期望的关于一兆字节是由 1000 还是 1024 KB 组成的转换。对于显示格式的第二部分,您可以从另一个 Stack Overflow 问题的答案开始:

How to convert int to currency?(他真的是在问如何插入逗号,而不是专门关于金钱的。)

但也许这个问题是错误的途径,因为那里的所有建议以及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;

【讨论】:

StrFormatByteSize64 似乎确实是 Windows 用于第一部分的内容。但是从 Delphi 调用该函数需要设置一个缓冲区 - 不漂亮。对于第二部分,floattostrf 似乎比您链接中的解决方案效果更好。 当您知道输出可以有多长时,请使用 char 的打包数组 [1..n] 作为缓冲区。传递 @CharArray[1] 作为指针。 很好的提示! (StrFormatByteSizeW) 自从Delphi XE,也许是Delphi 2010,你可以在ShLwApi.pas文件(Shell Ligtweight Utilities接口单元)中找到这些函数。【参考方案2】:

不完全是你所追求的,但我的库中有一个函数可以让你知道如何解决这个问题:

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;

【讨论】:

其他1000不应该也是1024吗?但相当简洁。 是的,从技术上讲它应该是 1024x1024x...但这是不久前为特定的视频服务器编写的。发布为一个简单的例子 如果除以 1024,您还应该使用 ISO 标准单位 TiB、GiB、MiB 和 KiB。 请不要使用 ISO“标准”,因为它毫无意义且视觉刺激【参考方案3】:

这是来自我的 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;

【讨论】:

以上是关于像 Windows 一样显示字节数的 Delphi 函数的主要内容,如果未能解决你的问题,请参考以下文章

Delphi:如何创建像 Skype 一样的 Windows 自动启动应用程序?

如何像在 Windows 资源管理器中一样在 Delphi 中获取排序顺序?

Delphi 编写的程序中,如何让程序实现像Windows7一样的毛玻璃效果?

怎样制作像delphi一样的启动欢迎画面?

delphi 动态获取文件类型的图标

一个delphi程序问题