关于获取文件大小,我有两个函数:
function GetFileSize1(const FileName: TFileName): Int64;
var
iTmp: Int64;
SearchRec: TSearchRec;
begin
iTmp := -1;
if FindFirst(FileName, faAnyFile, SearchRec) = 0 then
begin
iTmp := SearchRec.Size;
System.SysUtils.FindClose(SearchRec);
end;
Result := iTmp;
end;
和
function GetFileSize2(const FileName: TFileName): Int64;
var
FileStream: TFileStream;
begin
FileStream := TFileStream.Create(FileName, fmOpenRead);
try
Result := FileStream.Size;
finally
FileStream.Free;
end;
end;
在实践中,它有什么区别?当然,两者都返回相同的结果,但更加可信,更快,更安全?或者更好,什么是可取的用途?第一还是第二? 非常感谢。
答案 0 :(得分:8)
嗯,明显不同的是GetFileSize2
打开文件,使用CreateFile
API获取文件句柄。相反,GetFileSize1
不会,因为它从文件元数据中读取大小。
所以我希望GetFileSize1
表现得更好。虽然,对于许多应用程序而言,性能差异无关紧要。更重要的是,GetFileSize2
可能会因GetFileSize1
成功的情况下的共享冲突而失败。所以你真的不应该使用GetFileSize2
。
另请注意,出现错误时,您呈现的两个函数的行为会有所不同:GetFileSize1
返回-1,GetFileSize2
引发异常。
我个人更喜欢这个版本:
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;
或者,如果您希望在出现错误时返回-1,则可以这样写:
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;
有些人比调用FindFirstFile
感觉更自然,但这可能仅仅是个人偏好。 FindFirstFile
方法确实没有错。虽然它不需要iTmp
变量。你可以这样写清楚:
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;
更新: @CodeInChaos对未打开文件句柄的方法提出了一个很好的观点。这些方法可能会给硬链接文件带来不准确的结果。
答案 1 :(得分:1)
不同之处在于,GetFileSize1读取文件的元信息(Windows-API-Call),GetFileSize2直接触摸文件(获取FileHandle,一直走到最后计算大小)。
因此GetFileSize1比GetFileSize2消耗更少的性能/资源
更新
我忘了提及,如果文件已被使用,您可能不允许使用TFileStream访问,但元信息将可用。
更新(只是戴维斯的另一个变体建议)
function GetFileSize1(const FileName: TFileName): Int64;
var
SearchRec: TSearchRec;
begin
if FindFirst( FileName, faAnyFile, SearchRec ) = 0 then
try
Exit( SearchRec.Size );
finally
System.SysUtils.FindClose(SearchRec);
end;
Result := -1;
end;