我使用以下函数将Bytes格式化为更具人类可读性的格式,但它正在返回不正确的信息。
//Format file byte size
function FormatByteSize(const bytes: LongInt): string;
const
B = 1; //byte
KB = 1024 * B; //kilobyte
MB = 1024 * KB; //megabyte
GB = 1024 * MB; //gigabyte
begin
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;示例:
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(FormatByteSize(323889675684)); //Returns 1.65GB when it should be ~301GB
end;参考:http://delphi.about.com/od/delphitips2008/qt/format-bytes.htm (作者: Zarco )
有人能解释为什么它返回不正确的信息,更重要的是知道如何修复它从而返回正确的信息吗?
发布于 2015-05-02 05:53:40
问题是算术溢出。您可以如下所示的函数:
uses
Math;
function ConvertBytes(Bytes: Int64): string;
const
Description: Array [0 .. 8] of string = ('Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
var
i: Integer;
begin
i := 0;
while Bytes > Power(1024, i + 1) do
Inc(i);
Result := FormatFloat('###0.##', Bytes / Power(1024, i)) + #32 + Description[i];
end;发布于 2014-07-26 12:35:19
正如注释中所说的,您的问题是您的32位整数被64位值溢出,因此它被截断为32位(前32位被丢弃,所以f.ex )。5GB的值将被理解为1GB)。而且,由于您正在谈论的是大小,所以您确实不应该使用整数,因为这样您就会将一半的范围丢弃在在任何情况下都不能有效的值上(文件f.ex.不能有-2048字节的大小)。
我已经使用了以下两个函数一段时间了。没有小数参数的一个将返回最多3个小数,但只有在必要的情况下(即。如果大小正好是1GB,那么它将返回字符串“1GB”而不是“1000 Gb”(如果您的小数点是逗号)。
带有小数参数的那个总是返回带有这个小数的值。
还请注意,计算是使用二进制标度(1KB= 1024字节)完成的。如果希望将其更改为十进制,则应该用1000更改1024值,并可能更改SizeUnits数组。
CONST
SizeUnits : ARRAY[0..8] OF PChar = ('bytes','Kb','Mb','Gb','Tb','Pb','Eb','Zb','Yb');
FUNCTION SizeStr(Size : UInt64) : String; OVERLOAD;
VAR
P : Integer;
BEGIN
Result:=SizeStr(Size,3);
IF Size>=1024 THEN BEGIN
P:=PRED(LastDelimiter(' ',Result));
WHILE COPY(Result,P,1)='0' DO BEGIN
DELETE(Result,P,1);
DEC(P)
END;
IF CharInSet(Result[P],['.',',']) THEN DELETE(Result,P,1)
END
END;
FUNCTION SizeStr(Size : UInt64 ; Decimals : BYTE) : String; OVERLOAD;
VAR
I : Cardinal;
S : Extended;
BEGIN
S:=Size;
FOR I:=LOW(SizeUnits) TO HIGH(SizeUnits) DO BEGIN
IF S<1024.0 THEN BEGIN
IF I=LOW(SizeUnits) THEN Decimals:=0;
Result:=Format('%.'+IntToStr(Decimals)+'f',[S]);
Result:=Result+' '+StrPas(SizeUnits[I]);
EXIT
END;
S:=S/1024.0
END
END;如果您使用的是没有UInt64类型的Delphi编译器版本,则可以使用Int64 (您可能不会使用大于8EB= apprx的acros文件。8.000.000 TeraBytes在您的生命周期:-),所以Int64在这种情况下应该足够了)。
另外,CharInSet函数是来自Delphi版本的函数。可以将其定义为:
TYPE TCharacterSet = SET OF CHAR;
FUNCTION CharInSet(C : CHAR ; CONST Z : TCharacterSet) : BOOLEAN; INLINE;
BEGIN
Result:=(C IN Z)
END;或者直接在源代码中替换,如果您使用的是Delphi的前Unicode版本.
https://stackoverflow.com/questions/24970073
复制相似问题