Mega Code Archive

 
Categories / Delphi / Files
 

Reporting file size in a descriptive string

Title: Reporting file size in a descriptive string Question: 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 (2351) and NYB (2357) 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: 1. 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. 2.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' 3. Windows Explorer doesn't add space between a number and 'KB', 'MB', and 'GB', while both Adam's and NYB's functions do. 4. 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) 5. 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. //****************************************************************************** // // Unit Name: DPFileSize // Purpose : Functions for reporting file size with a descriptive string // Author : (c) 2001 Dmitri Papichev {Dmitri.Papichev@iname.com} // Comments : Specially for www.delphi3000.com // //****************************************************************************** unit DPFileSize; {==============================================================================} interface const KB = 1024; MB = KB*KB; GB = MB*KB; {main function} function GetFileSizeString (const AFileName: string): string; {helper functions, surfaced here as they might be used on their own} function DPGetFileSize (const AFileName: string): integer; function GetSignificantDigits (const ARealNumber: double; const ADigits: integer): string; function FormatFileSizeValue (const AValue: integer): string; {==============================================================================} implementation uses SysUtils, Classes; {------------------------------------------------------------------------------} {returns the string representing the file size for a given filename, in a way similar to what Windows Explorer does} function GetFileSizeString (const AFileName: string): string; begin try Result := FormatFileSizeValue (DPGetFileSize (AFileName)); except on E:Exception do begin Result := E.Message; end; {on} end; {if} end; {--GetFileSizeString--} {------------------------------------------------------------------------------} {returns file size in bytes for a given filename} function DPGetFileSize (const AFileName: string): integer; var AFileStream: TFileStream; begin AFileStream := TFileStream.Create (AFileName, fmShareCompat or fmShareDenyNone); try Result := AFileStream.Size; finally AFileStream.Free; end; {try} end; {--GetFileSizeDP--} {------------------------------------------------------------------------------} {returns first ADigits significant digits of ARealNumber, with a decimal point if any} function GetSignificantDigits (const ARealNumber: double; const ADigits: integer): string; begin if ADigits IN [1..16] then begin {that's the range of sig. digits supported} Result := Format ('%' + IntToStr (ADigits) + '.' + IntToStr (ADigits)+ 'f', [ARealNumber]); Result := Copy (Result, 1, ADigits + 1); if (Pos ('.', Result) IN [0, ADigits + 1]) then begin Result := Copy (Result, 1, ADigits); end; {if} end else begin raise Exception.Create ('GetSignificantDigits: '+ 'A number of significant digits out of range'); end; {if} end; {--GetSignificantDigits--} {------------------------------------------------------------------------} {converts given AValue to the string representing file size, in a way similar to what Windows Explorer does} function FormatFileSizeValue (const AValue: integer): string; begin case AValue of 0..999: begin Result := IntToStr (AValue) + ' bytes'; end; 1000..(MB - 1): begin Result := GetSignificantDigits (AValue/KB, 3) + 'KB'; end; MB..(GB - 1): begin Result := GetSignificantDigits (AValue/MB, 3) + 'MB'; end; else begin Result := GetSignificantDigits (AValue/GB, 3) + 'GB'; end; end; {case} end; {--FormatFileSizeValue--} end.