Author: Jonas Bilinkevicius
How to determine file and tree sizes larger 2 GB
Answer:
Solve 1:
You will need to use the FindFirstFile, FindNextFile and FindClose functions, e.g.:
1 function GetFileSize(const FileName: string): Int64;
2 var
3 F: TWin32FindData;
4 H: THandle;
5 begin
6 H := FindFirstFile(PChar(FileName), F);
7 if H = INVALID_HANDLE_VALUE then
8 RaiseLastWin32Error;
9 try
10 Result := F.nFileSizeHigh shl 32 + F.nFileSizeLow;
11 finally
12 Windows.FindClose(H);
13 end;
14 end;
15
16 function GetTreeSize(FileName: string): Int64;
17
18 procedure TreeSize(const FileName: string);
19 var
20 F: TWin32FindData;
21 H: THandle;
22 begin
23 H := FindFirstFile(PChar(FileName), F);
24 if H = INVALID_HANDLE_VALUE then
25 RaiseLastWin32Error;
26 try
27 repeat
28 if ((F.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) > 0) and
29 (F.cFileName[0]
30 <> '.') then
31 TreeSize(ExtractFilePath(FileName) + F.cFileName + '\*.*')
32 else
33 Result := Result + F.nFileSizeHigh shl 32 + F.nFileSizeLow;
34 until not FindNextFile(H, F);
35 finally
36 Windows.FindClose(H);
37 end;
38 end;
39
40 begin
41 Result := 0;
42 TreeSize(IncludeTrailingBackslash(ExtractFilePath(FileName)) + '*.*');
43 end;
I would add one little detail to your function. By calculating the filesize, you
should cast the values to Int64. In the helpfile you can read, that this is
necessary, because the operation would normally return an integer. In this case,
(F.nFileSizeHigh shl 32) would return an Integer and not an Int64.
Result := Int64(F.nFileSizeHigh) shl 32 + Int64(F.nFileSizeLow);
I think, casting "nFileSizeLow" is not necessary, but better to make it safe.
Solve 2:
Use the WinAPI version of the function GetFileSize() as follows:
44
45 procedure CardinalsToI64(var I: Int64; const LowPart, HighPart: Cardinal);
46 begin
47 TULargeInteger(I).LowPart := LowPart;
48 TULargeInteger(I).HighPart := HighPart;
49 end;
50
51 { ... }
52 var
53 fLOdword: dword;
54 fHIdword: dword;
55 FFilesize: Int64;
56 FFileHandle: THandle;
57 begin
58 FFileHandle := CreateFile(PChar(FFileName), GENERIC_READ, FILE_SHARE_READ, nil,
59 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
60 fLOdword := GetFileSize(FFileHandle, @fHIdword);
61 CardinalsToI64(FFilesize, fLOdword, fHIdword);
Solve 3:
62 function GetFileSize(const FileName: string): Int64;
63 var
64 SizeLow, SizeHigh: DWord;
65 hFile: THandle;
66 begin
67 Result := 0;
68 hFile := FileOpen(FileName, fmOpenRead);
69 try
70 if hFile <> 0 then
71 begin
72 SizeLow := Windows.GetFileSize(hFile, @SizeHigh);
73 Result := (SizeHigh shl 32) + SizeLow;
74 end;
75 finally
76 FileClose(hFile);
77 end;
78 end;
|