Verzeichnisgröße (Directory Size) ermitteln

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
Thorsten1867
Beiträge: 1360
Registriert: 04.02.2005 15:40
Computerausstattung: [Windows 10 x64] [PB V5.7x]
Wohnort: Kaufbeuren
Kontaktdaten:

Verzeichnisgröße (Directory Size) ermitteln

Beitrag 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)
Download of PureBasic - Module
Download of PureBasic - Programmes

[Windows 11 x64] [PB V6]

Bild
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Beitrag 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
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag 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)
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Benutzeravatar
Thorsten1867
Beiträge: 1360
Registriert: 04.02.2005 15:40
Computerausstattung: [Windows 10 x64] [PB V5.7x]
Wohnort: Kaufbeuren
Kontaktdaten:

Beitrag 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:
Download of PureBasic - Module
Download of PureBasic - Programmes

[Windows 11 x64] [PB V6]

Bild
Benutzeravatar
Thorsten1867
Beiträge: 1360
Registriert: 04.02.2005 15:40
Computerausstattung: [Windows 10 x64] [PB V5.7x]
Wohnort: Kaufbeuren
Kontaktdaten:

Beitrag von Thorsten1867 »

Kleines Problem:
FileSize: 3844842.0
FormatFileSize(): 3.67 MB
byterechner(): 4 KB
In jedem Fall eine geniale Komprimierung des Verzeichnisses. :lol:
Download of PureBasic - Module
Download of PureBasic - Programmes

[Windows 11 x64] [PB V6]

Bild
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag 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
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Benutzeravatar
Thorsten1867
Beiträge: 1360
Registriert: 04.02.2005 15:40
Computerausstattung: [Windows 10 x64] [PB V5.7x]
Wohnort: Kaufbeuren
Kontaktdaten:

Beitrag 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
Download of PureBasic - Module
Download of PureBasic - Programmes

[Windows 11 x64] [PB V6]

Bild
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag 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
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Jilocasin
Beiträge: 665
Registriert: 13.05.2006 16:04
Kontaktdaten:

Beitrag 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 :)
Bild
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag 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.
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Antworten