Author: Dmitri Papichev
How to tell the file size in a descriptive string like "2.33MB", or "233 bytes", as
Windows Explorer does in a status bar?
Answer:
The articles of Adam Lanzafame and NYB about file size string, and follow-up
discussions inspired me to come with a solution which would resolve some of the
issues of both aforementioned approaches/implementations (see the DPFileSize unit
attached below).
Some of these issues are:
Adam's function depends on the external library presence, specifically SHLWAPI.DLL
(Shell Light-weight Utility Library), which is essentially a helper library and may
not be installed on all systems.
For files from 1000 to 1023 bytes in size both Adam's and NYB's functions return
the size in bytes, while Windows Explorer displays '0.99KB'
Windows Explorer doesn't add space between a number and 'KB', 'MB', and 'GB', while
both Adam's and NYB's functions do.
NYB's function always displays two digits after a decimal point (even for bytes),
while the main idea of how Windows Explorer represents the number here is obviously
to keep three significant digits, including leading zero before decimal point (see
item 2 above)
NYB's function rounds the resulting value to the nearest value of the least
significant digit. The Windows Explorer approach seems to me as more consistent -
we may accept either one of the rounding directions, but it is better to be fixed.
The direction used by Explorer is towards lesser value of the least significant
digit, so it consistently shows that a file is at least of indicated size.
All these issues have been addressed in the unit below.
1
2 //******************************************************************************
3 //
4 // Unit Name: DPFileSize
5 // Purpose : Functions for reporting file size with a descriptive string
6 // Author : (c) 2001 Dmitri Papichev {Dmitri.Papichev@iname.com}
7 // Comments : Specially for www.delphi3000.com
8 //
9 //******************************************************************************
10
11 unit DPFileSize;
12
13 {==============================================================================}
14 interface
15
16 const
17 KB = 1024;
18 MB = KB * KB;
19 GB = MB * KB;
20
21 {main function}
22 function GetFileSizeString(const AFileName: string): string;
23
24 {helper functions, surfaced here as they might be used on their own}
25 function DPGetFileSize(const AFileName: string): integer;
26 function GetSignificantDigits(const ARealNumber: double;
27 const ADigits: integer): string;
28 function FormatFileSizeValue(const AValue: integer): string;
29
30 {==============================================================================}
31 implementation
32 uses
33 SysUtils,
34 Classes;
35
36 {------------------------------------------------------------------------------}
37 {returns the string representing the file size for a given filename, in a way
38 similar to what Windows Explorer does}
39
40 function GetFileSizeString(const AFileName: string): string;
41 begin
42 try
43 Result := FormatFileSizeValue(DPGetFileSize(AFileName));
44 except
45 on E: Exception do
46 begin
47 Result := E.message;
48 end; {on}
49 end; {if}
50 end; {--GetFileSizeString--}
51
52 {------------------------------------------------------------------------------}
53 {returns file size in bytes for a given filename}
54
55 function DPGetFileSize(const AFileName: string): integer;
56 var
57 AFileStream: TFileStream;
58 begin
59 AFileStream := TFileStream.Create(AFileName,
60 fmShareCompat or fmShareDenyNone);
61 try
62 Result := AFileStream.Size;
63 finally
64 AFileStream.Free;
65 end; {try}
66 end; {--GetFileSizeDP--}
67
68 {------------------------------------------------------------------------------}
69 {returns first ADigits significant digits of ARealNumber,
70 with a decimal point if any}
71
72 function GetSignificantDigits(const ARealNumber: double;
73 const ADigits: integer): string;
74 begin
75 if ADigits in [1..16] then
76 begin {that's the range of sig. digits supported}
77 Result := Format('%' +
78 IntToStr(ADigits) + '.' +
79 IntToStr(ADigits) + 'f', [ARealNumber]);
80
81 Result := Copy(Result, 1, ADigits + 1);
82 if (Pos('.', Result) in [0, ADigits + 1]) then
83 begin
84 Result := Copy(Result, 1, ADigits);
85 end; {if}
86 end
87 else
88 begin
89 raise Exception.Create('GetSignificantDigits: ' +
90 'A number of significant digits out of range');
91 end; {if}
92 end; {--GetSignificantDigits--}
93
94 {------------------------------------------------------------------------}
95 {converts given AValue to the string representing file size, in a way similar
96 to what Windows Explorer does}
97
98 function FormatFileSizeValue(const AValue: integer): string;
99 begin
100 case AValue of
101 0..999:
102 begin
103 Result := IntToStr(AValue) + ' bytes';
104 end;
105 1000..(MB - 1):
106 begin
107 Result := GetSignificantDigits(AValue / KB, 3) + 'KB';
108 end;
109 MB..(GB - 1):
110 begin
111 Result := GetSignificantDigits(AValue / MB, 3) + 'MB';
112 end;
113 else
114 begin
115 Result := GetSignificantDigits(AValue / GB, 3) + 'GB';
116 end;
117 end; {case}
118 end; {--FormatFileSizeValue--}
119
120 end.
|