Komplette Verzeichnisbäume löschen

Veröffentlicht: 04. Sep 2003 | Aktualisiert: 11. Nov 2004

Von Mathias Schiffer

Die Microsoft Newsgroups sind eine Quelle schier unerschöpflichen Wissens, das nahezu auf Knopfdruck abrufbar ist: Hunderte deutschsprachige Entwickler vom Einsteiger bis zum Profi treffen sich hier täglich virtuell, um Fragen zu stellen oder zu beantworten. Auch themennahe Probleme, Ansichten und Konzepte werden miteinander diskutiert. Sie kennen die Microsoft Newsgroups noch nicht? Detaillierte Information für Ihre Teilnahme finden Sie auf der Homepage der Microsoft Support Newsgroups.

Diese Kolumne greift regelmäßig ein besonders interessantes oder häufig nachgefragtes Thema aus einer der Entwickler-Newsgroups auf und arbeitet es aus.

Aus der Visual Basic Newsgroup microsoft.public.de.vb:

Frage: Wie kann ich in Visual Basic 6.0 einen kompletten Verzeichnisbaum von meiner Festplatte löschen?

Während Visual Basic dieses Ansinnen nicht direkt selber unterstützt, gibt es eine ganze Reihe von Möglichkeiten, dieses Ziel zu erreichen. Gleich vier davon sollen hier vorgestellt und erörtert werden.

Ansatz 1: Löschen per Kommandozeilenhilfe
Aus DOS und Windows 9x/Me kennen Sie vielleicht den DELTREE-Befehl, der einen Verzeichnisbaum komplett löscht. Unter Windows NT/2000/XP, das den DELTREE-Befehl nicht unterstützt, können Sie auf der Konsole den gleichen Effekt durch die Verwendung von "RD /S Verzeichnisname" erreichen (RD steht dabei für "Remake Directory" und der Zeilenschalter /S für "Subdirectories").

Zwar liegt es nahe, diesen Kommandozeilenbefehl aufzurufen, um das angefragte Ziel auf die Schnelle zu erreichen. Natürlich haben Sie jedoch keine Kontrolle darüber, ob der so angestoßene Vorgang erfolgreich beendet wurde. Zusätzlich bedarf es eines gewissen Aufwands zu ermitteln, wann die Löschaktion überhaupt abgeschlossen wurde.

Aus den angegebenen Gründen soll dieser Lösungsgedanke hier nicht weiter vertieft werden - er verlangt zu viel Aufwand für zu wenig Leistung. Möchten Sie diesen Weg dennoch beschreiten, so werden Ihnen die beiden folgenden Tipps des MSDN Quickie helfen:

Ansatz 2: Visual Basic pur - rekursives Löschen
Eine weitere Möglichkeit besteht darin, die VB-eigenen Methoden Kill (zum Löschen von Dateien) und RmDir (zum Löschen leerer Verzeichnisse) zu verwenden.

Hierfür ist es notwendig, rekursiv den zu löschenden Verzeichnisbaum zu durchwandern, um von der tiefsten Ebene bis zur obersten Ebene hin zunächst Dateien in Verzeichnissen zu löschen und erst danach die Verzeichnisse selbst zu entfernen.

Für dieses rekursive Vorgehen kann eingeschränkt die Dir-Funktion verwendet werden. Zwar ist sie eigentlich nicht "rekursionsfest" (ein parameterloser Folgeaufruf folgt immer auf den letzten mit Parametern ausgeführten Dir-Aufruf, der bei Rekursion auch in einer anderen Rekursionsebene aufgetreten sein kann). Durch geschickten Einsatz von Parametern im Bedarfsfall jedoch kann auch dieses kleine Manko umgangen werden.

Der folgende Sourcecode demonstriert Ihnen, wie Sie allein mit Mitteln aus Visual Basic rekursiv einen Verzeichnisbaum löschen können. Zur Fehlerauswertung wird hier lediglich der Rückgabewert der Funktion verwendet, der entweder Erfolg oder Misserfolg meldet. Selbstverständlich können Sie eine viel granularere Fehlerbehandlung einbauen (etwa wie auskommentiert vorgeschlagen).

Public Function DelTreeVB(ByVal Path As String) As Boolean 
' Löscht mit reinen Visual Basic-Methoden einen 
' Verzeichnisbaum (sofern möglich), indem rekursiv mit 
' Dir$, Kill und RmDir gearbeitet wird. 
' Kann der Baum nicht komplett gelöscht werden, wird als 
' Funktionsrückgabewert FALSE verwendet. 
' Hinweis: Die Dateien werden direkt gelöscht, nicht 
' lediglich in den Papierkorb verschoben (VB-Funktion Kill)! 
Dim sName As String 
  ' Backslash-Zeichen notwendigenfalls anhängen 
  If Right$(Path, 1) <> "\" Then 
 Path = Path & "\" 
  End If 
  ' Ziel: Funktionsrückgabewert TRUE 
  DelTreeVB = True 
  On Error GoTo Error_DelTree1 
  ' Das erste Element in Path suchen 
  sName = Dir$(Path & "*.*", vbHidden + vbDirectory) 
  ' Solange Elemente gefunden werden... 
  While Len(sName) 
 ' Pseudo-Verzeichnisse "." und ".." ignorieren 
 If (sName <> ".") And (sName <> "..") Then 
   ' Untersuchen, ob die Fundstelle eine Datei 
   ' oder ein Verzeichnis ist: 
   If (GetAttr(Path & sName) Or vbDirectory) = vbDirectory Then 
  ' Es handelt sich um ein Verzeichnis. 
  DelTreeVB = DelTreeVB(Path & sName & "\") 
  sName = Dir$(Path & "*.*", vbHidden + vbDirectory) 
   Else 
  ' Es handelt sich um eine Datei 
  SetAttr Path & sName, vbNormal ' Attribute zurücksetzen 
  Kill Path & sName  ' Datei löschen 
  sName = Dir$()  ' nächste Datei suchen 
   End If 
 Else 
   ' Bei "." oder ".." nächstes Element suchen 
   sName = Dir$() 
 End If 
  Wend 
  ' Unterverzeichnis durchlaufen - keine Dateien oder 
  ' Unterverzeichnisse mehr vorhanden: Das Verzeichnis 
  ' selber kann nun geloescht werden. 
  RmDir Path 
Exit_DelTreeVB: 
  Exit Function 
Error_DelTreeVB: 
  ' Funktiosrückgabewert FALSE 
  DelTreeVB = False 
  Resume Next 
'  ' Optional: Interaktion mit dem Anwender (Beispiel): 
'  Select Case MsgBox(Path & sName & vbNewLine _ 
'   & "konnte nicht gelöscht werden:" _ 
'   & vbNewLine & Err.Description, _ 
'   vbAbortRetryIgnore + vbDefaultButton2, _ 
'   "Fehler beim Löschen") 
' Case vbAbort:  Resume Exit_DelTreeVB 
' Case vbRetry:  Resume 0 
' Case vbIgnore: Resume Next 
'  End Select 
End Function

Ansatz 3: Methodenaufruf des FileSystemObject aus der Scripting-Runtime
Die dritte hier vorgestellte Möglichkeit zur Löschung eines Verzeichnisbaums nutzt die Bibliothek "Scripting Runtime", die sich in der DLL ScrRun.Dll verbirgt. Verwenden Sie diese Möglichkeit, müssen Sie diese Datei mit Ihrer Anwendung gemeinsam ausliefern.

Dieser Umstand erhöht zwar, wie jede zusätzliche Datei in Ihrem Setup, das Problempotential bei der Installation Ihrer Anwendung. Dafür aber liefert Ihnen das FileSystemObject aus der "Scripting Runtime" eine absolut simple Möglichkeit, einen Verzeichnisbaum zu löschen: Sie rufen einfach seine Methode DeleteFolder-Methode auf und übergeben den betroffenen Pfad:

Public Function DelTreeFSO(ByVal Path As String) As Boolean 
' Löscht mithilfe des FileSystemObject (ScrRun.dll) einen 
' Verzeichnisbaum (sofern möglich). 
' Kann der Baum nicht komplett gelöscht werden, wird als 
' Funktionsrückgabewert FALSE verwendet. 
' Hinweis: Die Dateien werden direkt gelöscht, nicht 
' lediglich in den Papierkorb verschoben! 
Dim FSO As Object 
  On Error Resume Next 
  ' FileSystemObject instanzieren 
  Set FSO = CreateObject("Scripting.FileSystemObject") 
  ' Konnte das Objekt instanziert werden? 
  If Err.Number <> 0 Then 
 Exit Function 
  End If 
  ' Die DeleteFolder-Methode des Objekts aufrufen 
  FSO.DeleteFolder Path, True 
  ' Trat beim Löschen ein Fehler auf? 
  If Err.Number <> 0 Then 
 Exit Function 
  End If 
  ' Fehlerfreie Abarbeitung => Rückgabewert TRUE 
  DelTreeFSO = True 
End Function

Ansatz 4: Löschen wie Windows selber - inkl. Papierkorb
Die vierte vorgestellte Möglichkeit brilliert vor allem durch einen besonderen Vorteil: Mithilfe des Windows API können Sie nicht nur einen Verzeichnisbaum komplett löschen. Sie können sogar Verzeichnisse und / oder Dateien sogar in den Windows-Papierkorb verschieben, statt sie unwiederbringlich zu löschen.

Hierfür verwenden Sie die API-Funktion SHFileOperation, die auch der Windows Explorer selber für Dateioperationen wie Kopieren, Verschieben, Umbenennen und Löschen verwendet.

Die Steuerung dieser Funktion erfolgt über eine Struktur vom Typ SHFILEOPSTRUCT. In ihrem Element wFunc wird dabei die Art der gewünschten Operation angegeben: Für das Löschen wird hier die Konstante FO_DELETE übergeben. Im Element pFrom wird der zu löschende Verzeichnispfad angegeben; er wird zusätzlich mit zwei vbNullChar-Zeichen abgeschlossen. Schließlich wird über den Parameter fFlags das Aussehen und Verhalten der Operation bestimmt: In diesem Fall soll keine Benutzerinteraktion erfolgen (FOF_SILENT Or FOF_NOCONFIRMATION Or FOF_NOERRORUI). Durch Hinzufügen der Konstanten FOF_ALLOWUNDO zu fFlags wird bewirkt, dass der Verzeichnispfad nicht unwiederbringlich gelöscht, sondern in den Windows Papierkorb verschoben wird.

Lief der Aufruf von SHFileOperation erfolgreich ab, so returniert die Funktion den Wert 0. Dem Parameter fAnyOperationsAborted der SHFILEOPSTRUCT-Struktur kann nach der Rückkehr der Funktion entnommen werden, ob vorgesehene Dateioperationen während der Ausführung der Funktion abgebrochen wurden. Trägt der Parameter den Wert 0, war die Ausführung vollständig.

' --- Notwendige API-Deklarationen --- 
Private Const FO_DELETE As Long = &H3& ' Aktion: Löschen 
' Hier relevante Werte für SHFILEOPSTRUCT.fFlags 
Private Const FOF_SILENT As Long = &H4 
Private Const FOF_NOCONFIRMATION As Long = &H10 
Private Const FOF_ALLOWUNDO As Long = &H40 
Private Const FOF_NOERRORUI As Long = &H400 
Private Type SHFILEOPSTRUCT ' Argument für SHFileOperation 
  hWnd As Long  ' Elternfenster für Dialoge 
  wFunc As Long ' Auszuführende Operation (FO_*) 
  pFrom As String  ' Quelldateiliste 
  pTo As String ' Zieldateiliste 
  fFlags As Integer   ' Steuerung / Optik 
  fAnyOperationsAborted As Boolean  ' Abbruch erfolgt? 
  hNameMappings As Long  ' Handle auf Umbenennungsliste 
  lpszProgressTitle As String ' Dialogtitel/FOF_SIMPLEPROGRESS 
End Type 
Private Declare Function SHFileOperation _ 
  Lib "shell32.dll" Alias "SHFileOperationA" ( _ 
  ByRef lpFileOperationData As SHFILEOPSTRUCT _ 
  ) As Long 
' --- DelTreeApi-Implementation --- 
Public Function DelTreeApi(ByVal Path As String) As Boolean 
' Löscht einen Verzeichnisbaum (sofern möglich). 
' Kann der Baum nicht komplett gelöscht werden, wird als 
' Funktionsrückgabewert FALSE verwendet. 
' Hinweis: Die Dateien werden in den Windows-Papierkorb 
' verschoben, wenn der Anwender diesen nicht deaktiviert 
' hat. Möchten Sie den Papierkorb umgehen, entfernen Sie 
' die Konstante FOF_ALLOWUNDO aus SFOS.fFlags. 
Dim SFOS As SHFILEOPSTRUCT 
  ' Den Shell-Funktionsaufruf vorbereiten 
  With SFOS 
 .wFunc = FO_DELETE ' Aktion: Löschen 
 .pFrom = Path & vbNullChar & vbNullChar ' Dateiliste 
 .fFlags = FOF_ALLOWUNDO Or _ 
  FOF_SILENT Or _ 
  FOF_NOCONFIRMATION Or _ 
  FOF_NOERRORUI  ' Keine Benutzer- 
  ' Interaktion 
  End With 
  ' Operation ausführen und auswerten 
  DelTreeApi = ((SHFileOperation(SFOS) = 0) And _ 
 (SFOS.fAnyOperationsAborted = 0)) 
End Function