Well, the obvious difference is that GetFileSize2
opens the file, using the CreateFile
API to obtain a file handle. In contrast, GetFileSize1
does not because it reads the size from the file meta data.
So I would expect GetFileSize1
to perform better. Although, for many applications that performance difference would not matter. Much more significantly, GetFileSize2
can fail due to a sharing violation in situations that GetFileSize1
will succeed. So you really should not use GetFileSize2
.
Note also that the two functions you present behave differently in case of an error: GetFileSize1
returns -1, and GetFileSize2
raises an exception.
Personally I prefer this version:
function GetFileSize3(const FileName: string): Int64;
var
fad: TWin32FileAttributeData;
begin
if not GetFileAttributesEx(PChar(FileName), GetFileExInfoStandard, @fad) then
RaiseLastOSError;
Int64Rec(Result).Lo := fad.nFileSizeLow;
Int64Rec(Result).Hi := fad.nFileSizeHigh;
end;
Or, if you prefer to return -1 in case of error you would write it like this:
function GetFileSize3(const FileName: string): Int64;
var
fad: TWin32FileAttributeData;
begin
if not GetFileAttributesEx(PChar(FileName), GetFileExInfoStandard, @fad) then
exit(-1);
Int64Rec(Result).Lo := fad.nFileSizeLow;
Int64Rec(Result).Hi := fad.nFileSizeHigh;
end;
Some how this feels more natural than calling FindFirstFile
, but that's perhaps just personal preference. There's really nothing wrong with the FindFirstFile
approach. Although it doesn't need that iTmp
variable. You can write it more clearly like this:
function GetFileSize1(const FileName: TFileName): Int64;
var
SearchRec: TSearchRec;
begin
if FindFirst(FileName, faAnyFile, SearchRec) = 0 then
begin
Result := SearchRec.Size;
System.SysUtils.FindClose(SearchRec);
end
else
Result := -1;
end;
Update: @CodeInChaos makes a good point about the approaches that don't open a file handle. These approaches can give inaccurate results for hard linked files.