Directory Size

Windows specific forum
trather
User
User
Posts: 29
Joined: Sun Nov 07, 2004 9:57 pm

Directory Size

Post by trather »

I am trying to make a program that will get the size of a directory.

This is what I have done but the size doesn't come back with a number

Code: Select all

F_Name.s=""
Size.l = 0
Test.s = "C:\Documents and Settings\User"

If ExamineDirectory(0, Test, "*.*")
    Repeat
      FileType = NextDirectoryEntry()
      If FileType
        F_Name = DirectoryEntryName()
        Debug F_Name
        If F_Name = "My Documents"
          Size = DirectoryEntrySize()
        EndIf
         Debug Size
         Size = 0
        If FileType = 2 ; Directory type
        EndIf
      EndIf
     Until FileType = 0 
Else
  MessageRequester("Error","Can't examine this directory: ",0)
EndIf
User avatar
NoahPhense
Addict
Addict
Posts: 1999
Joined: Thu Oct 16, 2003 8:30 pm
Location: North Florida

Re: Directory Size

Post by NoahPhense »

This one works well, it's in the code archive on your system:

Make sure you keep that last / on there ..

Code: Select all

; English forum: http://purebasic.myforums.net/viewtopic.php?t=6585&highlight=
; Author: Freak
; Date: 16. June 2003

; But be aware that if you have many big files then the total size may be 
; reported incorrectly due to limitations (missing big numbers) in PureBasic... 

Procedure.l DirectorySize(ID.l, Directory.s) 
  Protected Size.l 
  If ExamineDirectory(ID, Directory, "*.*") 
    Repeat 
      Entry.l = NextDirectoryEntry() 
      If Entry = 1 
        Size + DirectoryEntrySize() 
      ElseIf Entry = 2 
        Name.s = DirectoryEntryName() 
        If Name <> ".." And Name <> "." 
          Size + DirectorySize(ID+1, Directory+Name+"\") 
          UseDirectory(ID) 
        EndIf 
      EndIf 
    Until Entry = 0 
  EndIf 
  ProcedureReturn Size 
EndProcedure 

; Use 0 as ID, it is only needed for the recursive calls 
Debug DirectorySize(0, "C:\Documents and Settings\administrator\My Documents\") 
;Debug DirectorySize(0, "C:\Windows\") 
- np
trather
User
User
Posts: 29
Joined: Sun Nov 07, 2004 9:57 pm

Post by trather »

I had tried that one but I was getting wrong number for the large directory. So I was trying to understand how to handle large directory over 3 gig .
Pupil
Enthusiast
Enthusiast
Posts: 715
Joined: Fri Apr 25, 2003 3:56 pm

Post by Pupil »

trather wrote:I had tried that one but I was getting wrong number for the large directory. So I was trying to understand how to handle large directory over 3 gig .
That's a bit more complex as PB at the moment don't support variable types that can store larger values than 4G approx. (unless you count floats but that probably isn't a good option here). There's some user libs around that let you deal with larger numbers...
fweil
Enthusiast
Enthusiast
Posts: 725
Joined: Thu Apr 22, 2004 5:56 pm
Location: France
Contact:

Post by fweil »

Just one possible way to solve this : do you need an accurate precision ?

This works well enough for very large folders and volumes :

Code: Select all

; English forum: http://purebasic.myforums.net/viewtopic.php?t=6585&highlight=
; Author: Freak
; Date: 16. June 2003

; But be aware that if you have many big files then the total size may be
; reported incorrectly due to limitations (missing big numbers) in PureBasic...

Procedure.f DirectorySize(ID.l, Directory.s)
  Protected Size.f
  If ExamineDirectory(ID, Directory, "*.*")
    Repeat
      Entry.l = NextDirectoryEntry()
      If Entry = 1
        Size + DirectoryEntrySize()
      ElseIf Entry = 2
        Name.s = DirectoryEntryName()
        If Name <> ".." And Name <> "."
          Size + DirectorySize(ID+1, Directory+Name+"\")
          UseDirectory(ID)
        EndIf
      EndIf
    Until Entry = 0
  EndIf
  ProcedureReturn Size
EndProcedure

; Use 0 as ID, it is only needed for the recursive calls
Debug DirectorySize(0, "C:\Documents and Settings\administrator\My Documents\")
;Debug DirectorySize(0, "C:\Windows\")
My avatar is a small copy of the 4x1.8m image I created and exposed at 'Le salon international du meuble à Paris' january 2004 in Matt Sindall's 'Shades' designers exhibition. The original laminated print was designed using a 150 dpi printout.
trather
User
User
Posts: 29
Joined: Sun Nov 07, 2004 9:57 pm

Post by trather »

Yes. I am trying to compair directory sizes to know if it needs to be copied. If the sizes are the same then I can skip but if I am not getting true numbers then I have a problem.
fweil
Enthusiast
Enthusiast
Posts: 725
Joined: Thu Apr 22, 2004 5:56 pm
Location: France
Contact:

Post by fweil »

So you could use extended integers. This would give you the exact bytes quantity.

Obviously Purebasic does not render it on the screen this is easy to save two longs somewhere for comparizon.
My avatar is a small copy of the 4x1.8m image I created and exposed at 'Le salon international du meuble à Paris' january 2004 in Matt Sindall's 'Shades' designers exhibition. The original laminated print was designed using a 150 dpi printout.
trather
User
User
Posts: 29
Joined: Sun Nov 07, 2004 9:57 pm

Post by trather »

I am not sure that I understand.
fweil
Enthusiast
Enthusiast
Posts: 725
Joined: Thu Apr 22, 2004 5:56 pm
Location: France
Contact:

Post by fweil »

You could use a structure to define a 64 bits variable like :

Structure Integer64
l1.l
l2.l
EndStructure

then receive the 64 bits value rendered using API functions, and compare both 32 bits longs stored somewhere with a later 64 bits value you would like to check.
My avatar is a small copy of the 4x1.8m image I created and exposed at 'Le salon international du meuble à Paris' january 2004 in Matt Sindall's 'Shades' designers exhibition. The original laminated print was designed using a 150 dpi printout.
User avatar
NoahPhense
Addict
Addict
Posts: 1999
Joined: Thu Oct 16, 2003 8:30 pm
Location: North Florida

Post by NoahPhense »

fweil wrote:You could use a structure to define a 64 bits variable like :

Structure Integer64
l1.l
l2.l
EndStructure

then receive the 64 bits value rendered using API functions, and compare both 32 bits longs stored somewhere with a later 64 bits value you would like to check.
Do you mean kind of like how we are handling doubles right now?

If so, can you throw together a quick example for us.. Sorry ;) if we don't
ask, we will never move forward mentally.

Much appreciated!

- np
fweil
Enthusiast
Enthusiast
Posts: 725
Joined: Thu Apr 22, 2004 5:56 pm
Location: France
Contact:

Post by fweil »

Well, sorry, I was busy and then lazy up to this morning to draw a small sample code.

This is there something I meant by using large integers returned from API functions. In this sample code I use the volume extended information, returning bytes numbers larger than 2GB.

It works easy and can be processed in any program I guess (but only Windows API. I don't know about other platforms).

Note that I show float recalculted values just for understanding on how to display it, as it is not necessary to convert large integers values to floats for comparison.

Then you can look forward in using other file or filesystem commands to process file size or directory size comparizons.

Tell me if you are on the way with this.

Code: Select all

;
; ULARGE_INTEGER is part of API structures integrated in Purebasic
;
;Structure ULARGE_INTEGER
;  LowPart.l
;  HighPart.l
;EndStructure


  DirectoryName.s = "C:\"
  ; returns 1 if processed well
  Debug GetDiskFreeSpaceEx_(@DirectoryName, @FreeBytesAvailableToCaller.ULARGE_INTEGER, @TotalNumberOfBytes.ULARGE_INTEGER, @TotalNumberOfFreeBytes.ULARGE_INTEGER)
  ; returns HighPart * $100000000 + LowPart value
  Debug FreeBytesAvailableToCaller\LowPart
  Debug FreeBytesAvailableToCaller\HighPart
  f.f = FreeBytesAvailableToCaller\HighPart * $10000 * $10000 + FreeBytesAvailableToCaller\LowPart
  Debug f
  ; idem
  Debug TotalNumberOfBytes\LowPart
  Debug TotalNumberOfBytes\HighPart
  f.f = TotalNumberOfBytes\HighPart * $10000 * $10000 + TotalNumberOfBytes\LowPart
  Debug f
  ; idem
  Debug TotalNumberOfFreeBytes\LowPart
  Debug TotalNumberOfFreeBytes\HighPart
  f.f = TotalNumberOfFreeBytes\HighPart * $10000 * $10000 + TotalNumberOfFreeBytes\LowPart
  Debug f
  CallDebugger
  
End
My avatar is a small copy of the 4x1.8m image I created and exposed at 'Le salon international du meuble à Paris' january 2004 in Matt Sindall's 'Shades' designers exhibition. The original laminated print was designed using a 150 dpi printout.
trather
User
User
Posts: 29
Joined: Sun Nov 07, 2004 9:57 pm

Post by trather »

Thank you for the code
.
I have been trying to use this some API command but I can only get the size of the whole drive. Even if I change the directory. I have tried both "C:\windows" and "C:\windows\" and I get the same answer if I do just "C:\". I must be missing something but what I need to be able to do is see the total size of on directory and any sub directories that might be there.

What I am trying to do is look at the "My Documents" of each user on an XP Computer and compair that to the a copy of that users "My Documents" that I have copied off of the local computer and put on a Network server that they don't have access to. If I can check the size of the whole "My Documents" and it is not the same as the one that I have saved then I will just recopy it.
User avatar
Droopy
Enthusiast
Enthusiast
Posts: 658
Joined: Thu Sep 16, 2004 9:50 pm
Location: France
Contact:

Post by Droopy »

Using PBOSL I Tweaked Freak code
No size limitation :D

Code: Select all

;/ Return size of the Directory ( in Byte ) as a String
;/ Required PBOSB ( BigNum )
; Author: Freak Tweaked by Droopy ( Added BigNum )
; Date: 16. June 2003 / Tweaked 9/10/05


Procedure.s DirectorySizeInternal(ID.l, Directory.s) 
  
  If ExamineDirectory(ID, Directory, "*.*") 
    Repeat 
      Entry.l = NextDirectoryEntry() 
      If Entry = 1
        Total.s=BIGNUMADD(Total.s,Str(DirectoryEntrySize()))
        
      ElseIf Entry = 2 
        Name.s = DirectoryEntryName() 
        If Name <> ".." And Name <> "." 
          Temp.s=DirectorySizeInternal(ID+1, Directory+Name+"\")
          Total.s=BIGNUMADD(Total.s,Temp.s)
          UseDirectory(ID) 
        EndIf 
      EndIf 
    Until Entry = 0 
  EndIf 
  ProcedureReturn Total.s
EndProcedure 

Procedure.s DirectorySize(Directory.s)
  If Left(Directory,1)<>"\" : Directory +"\":EndIf
  ProcedureReturn DirectorySizeInternal(0,Directory)
  
EndProcedure

;/ Test
#Directory="C:\Windows\"
MessageRequester(#Directory,DirectorySize(#Directory)+" Bytes")
User avatar
NoahPhense
Addict
Addict
Posts: 1999
Joined: Thu Oct 16, 2003 8:30 pm
Location: North Florida

Post by NoahPhense »

We're trying not to use a lib.. unless we can get the source..

But for the record. I tried that code, and it doesn't like my (3) 4.6gb files.

- np
User avatar
NoahPhense
Addict
Addict
Posts: 1999
Joined: Thu Oct 16, 2003 8:30 pm
Location: North Florida

Post by NoahPhense »

Thanks Fweil. That is what we were looking for. A way to store and play
with the large numbers.

So we'll probably have to go with API when getting dir sizes too.. because
the native pb commands, don't allow us to store large numbers.. ?

- np
Post Reply