Seite 1 von 2

Verzeichnisgröße (Directory Size) ermitteln

Verfasst: 31.10.2006 13:22
von Thorsten1867

Code: Alles auswählen

Procedure.s FormatFileSize(Size.d)
  Size / 1024
  If Size < 1024 ; KiloByte
    If Size < 100
      size$ = StrD(Size,2) ; '3.21 KB'
    ElseIf Size < 100
      size$ = StrD(Size,1) ; '32.1 KB'
    Else
      size$ = StrD(Size,0) ; '321 KB'
    EndIf
    If Left(StringField(size$,2,"."), 1) = "0" : size$ = StringField(size$,1,".") : EndIf
    ProcedureReturn size$+" KB"
  ElseIf Size < 1048576 ; MegaByte
    Size / 1024
    If Size < 10
      size$ = StrD(Size, 2) ; '6.54' MB'
    ElseIf Size < 100
      size$ = StrD(Size, 1) ; '65.4' MB
    Else
      size$ = StrD(Size, 0) ; '654' MB
    EndIf
    If Left(StringField(size$,2,"."), 1) = "0" : size$ = StringField(size$,1,".") : EndIf
    ProcedureReturn size$+" MB"
  Else ; GigaByte
    Size / 1048576
    If Size < 10
      size$ = StrD(Size, 2) ; '1.23 GB'
    ElseIf Size < 100
      size$ = StrD(Size, 1) ; '12.3 GB'
    Else
      size$ = StrD(Size, 0) ; '123 GB'
    EndIf
    If Left(StringField(size$,2,"."), 1) = "0" : size$ = StringField(size$,1,".") : EndIf
    ProcedureReturn size$+" GB"
  EndIf
EndProcedure

Procedure.d GetDirSize(directory.s)
  Define.d Sum = 0, Size
  If Right(directory,1) <> "\" : directory + "\" : EndIf
  UsedDirectory = ExamineDirectory(#PB_Any, directory, "*.*") 
  While NextDirectoryEntry(UsedDirectory) 
    entryname.s = DirectoryEntryName(UsedDirectory) 
    If entryname = "." Or entryname = ".." : Continue : EndIf
    Select DirectoryEntryType(UsedDirectory)
      Case #PB_DirectoryEntry_File
        Size = DirectoryEntrySize(UsedDirectory)
        Sum + Size
      Case #PB_DirectoryEntry_Directory
        Size = GetDirSize(directory+entryname)
        Sum + Size
    EndSelect
  Wend
  FinishDirectory(UsedDirectory)
  ProcedureReturn Sum
EndProcedure

Dir$ = PathRequester("Bitte wählen Sie ein Verzeichnis aus", "C:\")
Size.d = GetDirSize(Dir$) : Debug Size
size$ = FormatFileSize(Size) : Debug size$

MessageRequester("Directory Size", "Directory: "+Dir$+Chr(10)+"Size: "+size$, #MB_OK|#MB_ICONINFORMATION)

Verfasst: 31.10.2006 13:33
von ts-soft
Bei grossen Festplatten kommt ein invalider :roll:
Zeile 43: While NextDirectoryEntry(UsedDirectory)
Könnte ein Bug in PB sein. Ansonsten funktioniert es sehr gut.

Deklarierung von Variablen wäre nett (in Prozeduren Protected) :wink:

Gruß
Thomas

Verfasst: 31.10.2006 15:14
von AND51
Warum benutzt du nicht den Byterechner, den ich, nco2k und NtQ entwickelt haben? Schau einfach nochmal in dem Forum "Codes, Tipps & Tricks".

Dort findest du in dem Thread auf Seite 3 oder 4 meinen 4 Zeiler; kürzer geht's nicht. 8)

Verfasst: 31.10.2006 15:41
von Thorsten1867
Das sagst du mir jetzt erst?!? :wink:

Code: Alles auswählen

Procedure.s byterechner(byte.q, NbDecimals.c=0) 
  Protected Bytes.d=PeekQ(@byte), unit.c=Round(Log(Bytes)/Log(1024), 0) 
  ProcedureReturn StrD(Bytes/Pow(1024, unit) , NbDecimals*(unit > 1 And 1))+" "+StringField("Byte,KB,MB,GB,TB,PB,EB", unit, ",") 
EndProcedure
Ist wirklich geringfügig kürzer. :mrgreen:

Verfasst: 31.10.2006 16:00
von Thorsten1867
Kleines Problem:
FileSize: 3844842.0
FormatFileSize(): 3.67 MB
byterechner(): 4 KB
In jedem Fall eine geniale Komprimierung des Verzeichnisses. :lol:

Verfasst: 31.10.2006 21:26
von AND51
Hallo!

Danke für den tipp mit dem byterechner(), ich habe ihn überarbeitet.
Ich habe deine prozedur verbessert, meine läuft nun etwas schneller als deine :D
Außerdem kann man wählen, ob auch Unterordner in die Suche mit einbezogen werden sollen und ich habe eine sehr wichtige Abfrage eingebaut: Nämlich, ob ExamineDirectory() erfolgreich war. Dies ist sehr wichtig, denn wenn ein Verzeichnis nicht geöffnet werden konnte (z. B. "System Volume Information"), dann kann das Programm abstürzen. Dies ist bei mir einmal passiert, als ich Thorstens Code getestet habe.

Da ich einen neuen rechner habe und PB frisch installiert habe (ohne die Konfiguration meines alten rechners), komme ich mit den einrückungen noch nicht klar, entschuldigung.
Meine neue rechnerkonfiguration könnt ihr in meinem Profil einsehen.

Thorsten1867 => 594 ms
vs.
AND51 => 453 ms
~ 34,2 GB Daten (Laufwerk C:\)
Das meine prozedur sschneller ist, liegt daran, dass ich meine byterechner()-Prozedur verwende, statt die anderen Versionen, die im gleichnamigen Thread gepostet wurden. Außerdem habe ich wie Thorsten den Namen des aktuellen Elements auch in einer Variablen speichern lassen und ich habe eine IF-Abfrage und die Select-Abfrage zu einem Elseif-Block zusammengefasst.
Wenn rekursiv gesucht wird, wird dieses zwischenergebnis nicht in einer Variablen zwischengepseichert, sondern direkt der Gesamtgröße hinzuaddiert.

Mein code:

Code: Alles auswählen

Procedure.s byterechner(byte.q, NbDecimals.b=0) 
   Protected bytes.d=PeekQ(@byte), unit.b=Round(Log(bytes)/Log(1024), 0) 
   ProcedureReturn StrD(Bytes/Pow(1024, unit), NbDecimals*(unit > 0 And 1))+" "+StringField("Byte,KB,MB,GB,TB,PB,EB", unit+1, ",") 
EndProcedure

Procedure.q GetDirectorySize(pfad.s, rekursiv=1)
  If Not Right(pfad, 1) = "\"
    pfad+"\"
  endif
  Protected dir.l=ExamineDirectory(#PB_Any, pfad, ""), size.q
  If dir
    While NextDirectoryEntry(dir)
      Protected entryname.s=DirectoryEntryName(dir)
      If entryname = "." Or entryname = ".."
        Continue
      ElseIf DirectoryEntryType(dir) = #PB_DirectoryEntry_File
        size+DirectoryEntrySize(dir)
        Continue
      ElseIf rekursiv
        size+GetDirectorySize(pfad+entryname+"\", rekursiv)
        Continue
       EndIf
    Wend
    FinishDirectory(dir)
  EndIf
  ProcedureReturn size
EndProcedure

pfad$=PathRequester("GetDirectorySize() — AND51-Methode"+#CRLF$+"Bitte wählen Sie ein Verzeichnis aus", "C:\")
start=ElapsedMilliseconds()
Debug byterechner(GetDirectorySize(pfad$), 1)
Debug ElapsedMilliseconds()-start

Verfasst: 01.11.2006 10:18
von Thorsten1867
Irre ich mich oder ist das so noch schneller?

Code: Alles auswählen

Procedure.s byterechner(byte.q, NbDecimals.b=0) 
  Protected Bytes.d=PeekQ(@byte), unit.b=Round(Log(Bytes)/Log(1024), 0) 
  ProcedureReturn StrD(Bytes/Pow(1024, unit), NbDecimals*(unit > 0 And 1))+" "+StringField("Byte,KB,MB,GB,TB,PB,EB", unit+1, ",") 
EndProcedure 

Procedure.q GetDirectorySize(Path.s, rekursiv = #True) 
  Protected dir.l, Size.q, entry.s
  If Not Right(Path, 1) = "\" 
    Path+"\" 
  EndIf 
  dir = ExamineDirectory(#PB_Any, Path, "")
  If dir 
    While NextDirectoryEntry(dir) 
      entry = DirectoryEntryName(dir) 
      If entry = "." Or entry = ".."
        Continue
      ElseIf DirectoryEntryType(dir) = #PB_DirectoryEntry_File 
        Size + DirectoryEntrySize(dir) 
      ElseIf rekursiv 
        Size + GetDirectorySize(Path+entry+"\", rekursiv) 
      EndIf 
    Wend 
    FinishDirectory(dir) 
  EndIf 
  ProcedureReturn Size 
EndProcedure 

path$=PathRequester("GetDirectorySize() — ANDTH5167-Methode"+#CRLF$+"Bitte wählen Sie ein Verzeichnis aus", "C:\") 
start=ElapsedMilliseconds() 
Debug byterechner(GetDirectorySize(path$), 1) 
Debug ElapsedMilliseconds()-start

Verfasst: 01.11.2006 13:48
von AND51
Bei mir sind sie beide gleich schnell:
Ich: 469 ms
Du/Wir: 485 ms

Das komische ist: Als ich einen der Codes das erste mal ausführte, dauerte es 10.750 ms, die 34 GB Daten zu scannen. Schon aber beim zweiten Versuch dauerte es nur ~500 ms. Danach habe ich die Codes gegeneinander antreten lassen und dabei kam das oben beschriebene Ergebnis bei raus.

Dieser Unterschied ist zwar unbedeutend klein, genau genommen ist mein Code aber immer noch schneller. Du hast bei den beiden ElseIf-Blöcken das Continue wweggelassen! Continue bewirkt, dass der aktuelle Schleifendurchlauf abgebrochen und sofort wieder am Anfang (hier While) ausgeführt wird.
Bei deinem Code würde er, sofern entry nicht gleich ".." oder "." ist, erst einen der Else-If-Blöcke durchlaufen. Das ist normal und passiert bei mir auch. Aber bei mir wird dann am Ende des ElseIf-Blocks das continue ausgeführt. Bewirkt, dass r sofort wieder oben anfängt; das fehlt bei dir und deshalb springt dein Schleifendurchlauf erst dann nach While zurück, wenn er bei Wend landet.



Du musst aber schon zugeben, dass ich ein paar gute Ideen hatte, z. B. die Auswahl, ob rekursiv gescannt werden soll oder die Idee, dein Select durch ein If zu ersetzen... 8) :D

Verfasst: 01.11.2006 15:22
von Jilocasin
AND51 hat geschrieben:Das komische ist: Als ich einen der Codes das erste mal ausführte, dauerte es 10.750 ms, die 34 GB Daten zu scannen. Schon aber beim zweiten Versuch dauerte es nur ~500 ms. Danach habe ich die Codes gegeneinander antreten lassen und dabei kam das oben beschriebene Ergebnis bei raus.
Das liegt daran dass das OS beim zweiten Mal scannen nicht erneut die Festplatte schraddeln lässt, sondern das "vorherige Ergebnis" noch im speicher hat :)

Verfasst: 01.11.2006 15:24
von AND51
Genau, irgendsowas wirds sein. Dennoch ist das Ergebnis eindeutig/unterschiedlich. Thorsten1867 protected z. B. alle Variablen am anfang, ich erst, wenn sie gebraucht werden. Sind so Details in Sachen Geschmackssache.
Ich denke, im wesentlichen haben wir die Perfektion nahezu erreicht.