Error in findfirst file size

eNarc
eNarc used Ask the Experts™
on
Hi, I'm having problems with displaying the correct sum of files in a folder.

I've used

for some reason when I use the code below on a folder it brings back negative, even though the list that its adding is all positive.

I'm having trouble with both ways of getting the size.

is there a way of doing it so all files bring back the true size?
 
function Search(path:string;o:integer):string;
var
  sr : tsearchrec;
  res: integer;
  i  :integer;
  z:int64;
begin
  path:= includetrailingpathdelimiter(path);
  res:= findfirst(path+'*.*',faAnyfile,sr);
  while res = 0 do begin
    application.processmessages;
    if (sr.name <> '.') and (sr.name <> '..') then
      if DirectoryExists(path + sr.name) then begin


        Form32.Richedit1.lines.add('Folders: '+path+sr.name);
        Search(path + sr.name,o);
      end else begin

    //z:=Int64(sr.FindData.nFileSizeHigh) shl Int64(32) + Int64(sr.FindData.nFileSizeLow)+z;
      z:=Sr.Size;

        Filesizes:=Filesizes+z;

        Form32.Richedit1.lines.add('Files: '+path+sr.name);
      end;

    res := findnext(sr);
  end;
  findclose(sr);

end;

Open in new window

Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
The reason for the negative value is either you have a file in the folder that is greater than 2 GB or the folder as a whole is greater than 2 GB.

Try this:
program Project15;

{$APPTYPE CONSOLE}

uses
  SysUtils;

procedure FolderSize(Dir: String; var TotalSize: Int64);
var
  SearchRec : TSearchRec;
  FileSize : Int64;
begin
  Dir := IncludeTrailingBackslash(Dir);
  If FindFirst(Dir + '*', faAnyFile, SearchRec) = 0 Then
    begin
    If FileExists(Dir + SearchRec.Name) Then
      begin
      {$WARNINGS OFF}
      Int64Rec(FileSize).Lo := SearchRec.FindData.nFileSizeLow;
      Int64Rec(FileSize).Hi := SearchRec.FindData.nFileSizeHigh;
      {$WARNINGS ON}
      Inc(TotalSize, FileSize);
    end
    Else If DirectoryExists(Dir + SearchRec.Name) Then
      begin
      If (SearchRec.Name <> '.') And (SearchRec.Name <> '..') Then
        begin
        FolderSize(Dir + SearchRec.Name, TotalSize);
      end;
    end;
    While FindNext(SearchRec) = 0 Do
      begin
      If FileExists(Dir + SearchRec.Name) Then
        begin
        {$WARNINGS OFF}
        Int64Rec(FileSize).Lo := SearchRec.FindData.nFileSizeLow;
        Int64Rec(FileSize).Hi := SearchRec.FindData.nFileSizeHigh;
        {$WARNINGS ON}
        Inc(TotalSize, FileSize);
      end
      Else If DirectoryExists(Dir + SearchRec.Name) Then
        begin
        If (SearchRec.Name <> '.') And (SearchRec.Name <> '..') Then
          begin
          FolderSize(Dir + SearchRec.Name + '\',TotalSize);
        end;
      end;
    end;
  end;
  SysUtils.FindClose(SearchRec);
end;

var
  MyFolderSize : Int64;
begin
  FolderSize('X:\Movies', MyFolderSize);
  Writeln(MyFolderSize);
  Readln;
end.

Open in new window

Freelance Project Manager
Top Expert 2010
Commented:
ThievingSix, you are not initializing MyFolderSize to 0, which is hazardous.
A function would be better than a procedure with var parameter
About the 64bits size calculation, you might do it faster with bit SHIFT operator
and last, using FileExists and DirectoryExists is redundantly slow at best, if it has been found it exists. Use the Attr to determine if it's a file or directory instead.

function FolderSize(Dir: String): Int64;
var
  SearchRec : TSearchRec;
  FileSize : Int64;
  FindRes:Integer;
begin
 Result:=0;
 Dir := IncludeTrailingBackslash(Dir);
 FindRes:=FindFirst(Dir + '*.*', faAnyFile, SearchRec);
 While FindRes=0 do
  begin
   If (SearchRec.Name <> '.') And (SearchRec.Name <> '..') Then
    begin
     if (SearchRec.Attr And faDirectory)>0 
      Then Result:=Result+FolderSize(Dir+SearchRec.Name)
      Else Result:=Result+
            SearchRec.FindData.nFileSizeLow+
            SearchRec.FindData.nFileSizeHigh SHL 32;
    end;
   FindRes:=FindNext(SearchRec);
  end;
 FindClose(SearchRec);
end;

begin
  Writeln(FolderSize('X:\Movies'));
  Readln;
end.

Open in new window

Author

Commented:
I've Tested each code.

these are the results on a folder.

42.7 MB (44,828,786 bytes)

results.


ID:33132907>>ThievingSix>>19689242527465331
ID:33146717>>epasquier>>44828786
procedure FolderSize(Dir: String; var TotalSize: Int64);
var
  SearchRec : TSearchRec;
  FileSize : Int64;
begin
  Dir := IncludeTrailingBackslash(Dir);
  If FindFirst(Dir + '*', faAnyFile, SearchRec) = 0 Then
    begin
    If FileExists(Dir + SearchRec.Name) Then
      begin
      {$WARNINGS OFF}
      Int64Rec(FileSize).Lo := SearchRec.FindData.nFileSizeLow;
      Int64Rec(FileSize).Hi := SearchRec.FindData.nFileSizeHigh;
      {$WARNINGS ON}
      Inc(TotalSize, FileSize);
    end
    Else If DirectoryExists(Dir + SearchRec.Name) Then
      begin
      If (SearchRec.Name <> '.') And (SearchRec.Name <> '..') Then
        begin
        FolderSize(Dir + SearchRec.Name, TotalSize);
      end;
    end;
    While FindNext(SearchRec) = 0 Do
      begin
      If FileExists(Dir + SearchRec.Name) Then
        begin
        {$WARNINGS OFF}
        Int64Rec(FileSize).Lo := SearchRec.FindData.nFileSizeLow;
        Int64Rec(FileSize).Hi := SearchRec.FindData.nFileSizeHigh;
        {$WARNINGS ON}
        Inc(TotalSize, FileSize);
      end
      Else If DirectoryExists(Dir + SearchRec.Name) Then
        begin
        If (SearchRec.Name <> '.') And (SearchRec.Name <> '..') Then
          begin
          FolderSize(Dir + SearchRec.Name + '\',TotalSize);
        end;
      end;
    end;
  end;
  SysUtils.FindClose(SearchRec);
end;




procedure TForm1.Button2Click(Sender: TObject);
var
  MyFolderSize : Int64;
begin
  FolderSize('C:\1\', MyFolderSize);
  RichEdit1.Lines.Add(IntToStr(MyFolderSize));
end;






function FolderSize2(Dir: String): Int64;
var
  SearchRec : TSearchRec;
  FileSize : Int64;
  FindRes:Integer;
begin
 Result:=0;
 Dir := IncludeTrailingBackslash(Dir);
 FindRes:=FindFirst(Dir + '*.*', faAnyFile, SearchRec);
 While FindRes=0 do
  begin
   If (SearchRec.Name <> '.') And (SearchRec.Name <> '..') Then
    begin
     if (SearchRec.Attr And faDirectory)>0
      Then Result:=Result+FolderSize2(Dir+SearchRec.Name)
      Else Result:=Result+
            SearchRec.FindData.nFileSizeLow+
            SearchRec.FindData.nFileSizeHigh SHL 32;
    end;
   FindRes:=FindNext(SearchRec);
  end;
 FindClose(SearchRec);
end;



procedure TForm1.Button3Click(Sender: TObject);
begin
RichEdit1.Lines.Add(IntToStr(FolderSize2('C:\1\')));

end;

Open in new window

Author

Commented:
>>epasquier

I wasn't aware that you can pass along the results into another send function like below

Then Result:=Result+FolderSize(Dir+SearchRec.Name)
      Else Result:=Result+
            SearchRec.FindData.nFileSizeLow+
            SearchRec.FindData.nFileSizeHigh SHL 32;

wasn't aware of that, though now I am, it just never accord to me that I could send results through a function into another function with the results to combine all results at the very end, I like that, I could do so much with it now, thanks.

Author

Commented:
>>ThievingSix
after noticing the code was bring back a huge sum, I realized that yea it wasn't being initializing, so I've put.

MyFolderSize : Int64;

into global vars and its worked, results where 44828786
Emmanuel PASQUIERFreelance Project Manager
Top Expert 2010

Commented:
Result is just as a variable implicitly declared in all functions, you can use it many times in your calculations, it just have the additional property to be "returned" as result to the function
In assembler, it is the (E)AX register

instead of putting the MyFolderSize in globals, you would just have to set it to 0 before calling his procedure. Try to avoid global variables as much as possible, that is not good practice and it is hell on earth to have to maintain some code where there are too much of those. Usually, apart from Delphi own globals such as Application, Screen etc.. you  should have only the forms and datamodules that are globals. And even that is when there can be only one instance of them

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial