Seite 2 von 3

Verfasst: 22.01.2007 17:37
von AND51
CNESM hat geschrieben:Was mit jetzt noch ein Problem aufwirft, ist das von AND51 aufgezeigte Verhalten der Procedur (Danke schonmal dafür!!). Hatte ich im ganzen Hin und Her nicht beachtet!
Kein Problem! :) Dieses Problem habe ich entdeckt, als ich einen eigenen FileCleaner schreiben wollte, der auch leere Ordner löschen sollte.

Die einzige Lösung ist folgende:
Wenn ich feststelle, dass "C:\myOrdner\temp" doch nich leer ist, darf ich ihn nur löschen, wenn "C:\myOrdner\temp\leer" leer ist. Mit anderen Worten: Ich darf einen Ordner nur löschen, wenn alle anderen Ordner da drin auch leer sind (beachte: in "temp" könnten ja zum Beispiel auch die Ordner "leer1" und "leer2" enthalten sein).

Lösungsanzsatz: Ich würde versuchen, so rekursiv zu arbeiten, wie viele Beispielcode aus diesem Forum. (So wie vonTurnundTaxis.) Dabei sollte die Mödlichkeit, mit ProcedureReturn einen Wert zurückgeben zu können, unbedingt genutzt werden; beispielsweise um die Anzahl der Dateien im aktuellen Order zurückzugeben.

Beispiel: Ich scanne den Ordner "C:\myOrdner\temp". Wegen der Rekusivität ruft sich die Procedure selbst nocheinmal auf und scannt "C:\myOrdner\temp\leer". Es wird die zahl 0 zurückgegeben, weil 0 Dateien im Ordner "leer" sind. Diese Zahl 0 wird zu der Gesamtanzahl der Dateien hinzuaddiert, die im Ordner "C:\myOrdner\temp" entahlen sind. Die Summe lautet 0, es sind also 0 Dateien in temp + 0 Dateien in leer. Das Ergebnis 0gibst du wiederum mit ProcedureReturn zurück, und so weiter. Ein Verzeichnis darf dann nur gelöscht werden, wenn das Ergebnis 0 ist.

Wie gesagt, in vonTurnundTaxis' Code kannst du das gut sehen. Allerdings solltest du auf
> If Not_Empty = 0
verzichten und stattdessen
> If Not Not_Empty
verwenden. (Daran sieht man, wer sich schon wie weit auf die neuen PB 4-Features eingelassen hat :wink: ).


@ vonTurnundTaxis: Warum benutzt du kein BREAK nach der Zeile, in der du Not_Empty auf 1 setzt? Dann wird dein Code sehr viel schneller! Aber bitte, wenn du nicht magst... :wink:

Verfasst: 22.01.2007 17:43
von HeX0R
AND51 hat geschrieben: Allerdings solltest du auf
> If Not_Empty = 0
verzichten und stattdessen
> If Not Not_Empty
verwenden.
Warum ?

Verfasst: 22.01.2007 17:47
von NicTheQuick
AND51 hat geschrieben:@ vonTurnundTaxis: Warum benutzt du kein BREAK nach der Zeile, in der du Not_Empty auf 1 setzt? Dann wird dein Code sehr viel schneller! Aber bitte, wenn du nicht magst... :wink:
Weil noch weitere leere Unterordner folgen könnten, die gelöscht werden
sollen. Mit ExamineDirectory() aufgelistete Dateien können bunt
durcheinandergewürfelt zurückgegeben werden.

Verfasst: 22.01.2007 17:51
von AND51
@ HeXor: Warum nicht?

@ NtQ: Stimmt, daran habe ich nicht gedacht, SRY

Verfasst: 23.01.2007 00:08
von HeX0R
AND51 hat geschrieben:@ HeXor: Warum nicht?
[OT (Sorry)]
Eigentlich war ich der Meinung, das PB so g'scheit ist, das gleich zu interpretieren.
Hab mir aber den ASM-Output angesehn :
Not :

Code: Alles auswählen

; a = 1
  MOV    dword [v_a],1
; If Not a
  CMP    dword [v_a],0
  JE     No0
  XOR    eax,eax
  JMP    Ok0
No0:
  MOV    eax,1
Ok0:
  AND    eax,eax
  JE    _EndIf2
; a = 2
  MOV    dword [v_a],2
; EndIf
_EndIf2:
= 0

Code: Alles auswählen

; a = 1
  MOV    dword [v_a],1
; If a = 0
  MOV    ebx,dword [v_a]
  AND    ebx,ebx
  JNE   _EndIf2
; a = 2
  MOV    dword [v_a],2
; EndIf
_EndIf2:
irgendwie seltsam... ausm Bauch raus, ohne irgendwelche Geschwindigkeiten der Befehle zu kennen, würde ich sagen, die =0-Methode sollte schneller sein.
[/OT]

Verfasst: 23.01.2007 01:10
von AND51
[OT]
Toll! Wieder nen Feature, das in Wahrheit nix taugt. Algengrütze und Walfischdreck! Bild
Gibt's noch mehr davon?
[/OT]

Verfasst: 23.01.2007 20:49
von CNESM
Also Leute, hab die zwei Codes mal getestet und ich muss sagen: Ihr habt mir den Arsch gerettet :mrgreen:

Beide Codes erfüllen ihren Zweck, sind lauffähig und schnell. Wer jedoch einen Tick schneller ist, werde ich morgen mal testen - nach dem Meeting.

@ NicTheQuick

Ein hervorragendes Beispiel. Hätte nichts anderes von dir erwartet :allright: Das Arbeiten mit Strukturen bringt einen gewisse Übersicht und hat den Vorteil, das gewisse Auswertungen möglich sind, da die Verzeichnissinhalte in diesem Fall "protokolliert" werden. Ist vielleicht in meinen Fall sogar vom Vorteil, um nachweisen zu können, wie er die einzelnen Ordner behandelt hat! Schlielich handelt es sich dabei um wichtige Daten, die zwar Backup gesichert sind, aber dennoch teilweisen großen Wert haben!

@ vonTurnundTaxis

Auch dein Beispiel ist natülrich sehr gut umgesetzt. Einfaches Beispiel, vor allem für Anfänger wie mich, deutlich leichter zu verstehen, als das doch komplexere Beispiel von Nic. Finde diesen Vergleich der Lösungen hervorragend, da man so sieht, welche Möglichkeiten es gibt, das Problem anzugehen. Ein Schönheitsfehler ist mir bei deinem Code aber aufgefallen:

Da du scheinbar mit + "/" + arbeitest, werden die unteresten Verzeichnisse "falsch" ausgegeben (Beispiel: C:\Leer\/Leer\Leer) , da ja teilweise bereits ein "/" vorhanden ist. Tut der Funktion keinen Abbruch. Vielleicht den Code einfach um folgende Zeilen ergänzen?

Code: Alles auswählen

Procedure DeleteEmptyFolders(Folder.s) 
    Protected ID 
    Protected Not_Empty 
    ID = ExamineDirectory(#PB_Any, Folder, "*") 
    
    While NextDirectoryEntry(ID) 
        Select DirectoryEntryType(ID) 
            Case #PB_DirectoryEntry_Directory 
                If DirectoryEntryName(ID) <> "." And DirectoryEntryName(ID) <> ".." 
                   If Right(Folder,1)="\" Or Right(Folder,1)="/"
                      Not_Empty + IsFolderEmpty(Folder + DirectoryEntryName(ID))
                   Else
                      Not_Empty + IsFolderEmpty(Folder + "/" + DirectoryEntryName(ID)) 
                   EndIf
                EndIf 
            Case #PB_DirectoryEntry_File 
                Not_Empty = 1 
        EndSelect 
    Wend 
    FinishDirectory(ID) 
    If Not_Empty = 0 
        DeleteDirectory(Folder, "*") 
    EndIf 
    ProcedureReturn Not_Empty 
EndProcedure 


DeleteEmptyFolders("/Blöder/böser/Pfad")
Melde mich morgen mit Erfahrungsbericht zurück!

Verfasst: 24.01.2007 02:43
von AND51
Halt!

Nimm lieber meinen Code! Denn deiner enthält Fehler und kann noch verschnellert und drastisch verkürzt werden!!

Code: Alles auswählen

Procedure DeleteEmptyFolders(path.s) ; AND51
	Protected empty, dir=ExamineDirectory(#PB_Any, path, "")
	If dir
		While NextDirectoryEntry(dir)
			If DirectoryEntryType(dir) = #PB_DirectoryEntry_File
				empty=1
				Continue
			ElseIf DirectoryEntryName(dir) <> "." And DirectoryEntryName(dir) <> ".."
				empty+DeleteEmptyFolders(path+DirectoryEntryName(dir)+"\")
			EndIf
		Wend
		FinishDirectory(dir)
		If Not empty
			DeleteDirectory(path, "", #PB_FileSystem_Recursive)
		EndIf
	EndIf
	ProcedureReturn empty
EndProcedure

Debug DeleteEmptyFolders("C:\")
Zu deinem Code:
-Warum übergibst du überall bei ExamineDirectory() und DeleteDirectory() ein Stern? Ein Leerstring reicht doch auch.
-Du prüfst gar nicht, ob das Verzeichnis erfolgreich gescannt werden konnte, das führt zu Abstürzen, wenn der Benutzer z. B: keine Leserechte hat!
-Warum auf #PB_DirectoryEntry_File und #PB_DirectoryEntry_Directory prüfen? Sieh dir meinen Code an, der macht aus deinem 'Select+If+If' Konstrukt ein einfaches 'If'. Nebenbei reicht, es nur zu prüfen, ob es sich um eine Datei handelt - falls nicht, kann es logischerweise nur ein Verezichnis sein, ich spare also die Extraprüfung nach #PB_DirectoryEntry_Directory.
-Das benutzen des Schlüsselwortes Continue spart sehr viel Zeit bem Scannen ganzer Festplatten nach leeren Ordnern. Meine Festplatte (C:, 298 GB, 426 leere Ordner) wird im Debuggermodus in nur 5 Sekunden gescannt (mit ausgeschaltetem Debugger weitaus schneller).
-Dein Code ist fehlerhaft: Deine Procedure heißt 'DeleteEmptyFolders', du rufst aber zwei Mal 'IsFolderEmpty' auf.
-Unter Windows reicht es, nur mit \ statt / zu arbeiten. Außerdem haben Pfade in PureBasic immer ein \ am Ende, sonst ist es in PB kein korrekter Pfad. Die Debuggerausgabe von deinem Code liefert pro Pfad jedoch gleich 2 Fehler:
> C:\WINDOWS/system32/WINSxS
1. Warum mixt du / und \ ??
2. Am Ende fehlt ein (Back-)Slash! Solche Pfade arbeiten mit PB nur unkorrekt (Beispielsweise würde FileSize() ein falsches Ergebnis liefern, selbst wenn der eben genannte Pfad ein Ordner ist).
-Wenn man ordentlich programmiert, braucht man keine Prüfung, die gegebenenfalls manuell ein (Back-)Slash anhängt; PB-Pfade haben sowieso immer ein Backslash am Ende (beispielsweise gibt PathRequester() immer solche korrekten Pfade zurück). Dadurch, dass man diese Prüfung wegfallen lassen kann, erhört sich nochmals die Geschwindigkeit des Codes.

>>>> Ich hoffe, ich konnte dir mit den vielen Tipps helfen <<<<


Tipp: Sieh dir meine Procedure an; es gibt kaum einen Code, der kompakter/schneller ist, würde ich jetzt enfach mal so aus dem Stehgreif behaupten. Darfst du aber natürlich trotzdem gern noch umschreiben/anpassen, etc. So wie's dir halt gefällt.
Wenn jemand noch eine knackigere Version hat, her damit, bin daran interessiert! :)

Verfasst: 24.01.2007 06:01
von edel
-Wenn man ordentlich programmiert, braucht man keine Prüfung, die gegebenenfalls manuell ein (Back-)Slash anhängt;
Schwachsinn, was hat das mit programmieren zu tun wenn der User
eine Eingabe ohne Backslash macht, was ja nicht mal verkehrt ist ?

Verfasst: 24.01.2007 07:58
von vonTurnundTaxis
Was redet der Kerl da?

@AND:
Dein Code braucht bei mir übrigens doppelt so lange wie meiner, in einem Testszenario mit 828 Ordnern. Allerdings mit dem Ergebnis, dass auch die nicht-leeren Ordner gelöscht wurden.