Mit Dateien und Verzeichnissen arbeiten

Wer unter Visual Studio Anwendungen mit Visual Basic programmiert, wird früher oder später an den Punkt kommen, wo er mit Dateien und Verzeichnissen arbeitet. Dabei gibt es Aufgaben wie zu ermitteln, ob eine Datei bereits vorhanden ist, eine Datei von einem Verzeichnis in ein anderes zu kopieren, alle Dateien eines Verzeichnisses zu durchlaufen oder dies gar rekursiv für untergeordnete Verzeichnisse und Dateien zu erledigen. Natürlich bietet Microsoft passende Möglichkeiten an, die kaum noch etwas mit den von VBA gewohnten Befehlen zu tun haben und auch nicht mit den Methoden des FileSystemObjects.

Die Beispiele dieses Artikels haben wir mit dem Tool LINQPad durchgespielt, das die einfache Eingabe von Visual Basic- und C#-Anweisungen und deren Ausführung erlaubt. Sie müssen hier nicht immer erst das Projekt kompilieren, um die enthaltenen Anweisungen zu debuggen, sondern können dies quasi ad hoc erledigen (Download siehe https://www.linqpad.net).

Der Namespace System.IO

Die Objekte, Methoden und Eigenschaften, die wir in diesem Artikel vorstellen, befinden sich im Namespace System.IO. Um diesen für eine Datei in LINQPad verfügbar zu machen, betätigen Sie die Taste F4. Dadurch wird der Dialog Query Properties geöffnet. In diesem wechseln Sie zum zweiten Registerreiter Additional Namespace Imports. Hier tragen Sie einfach wie in Bild 1 den folgenden Namespace ein:

Hinzufügen von Namespaces

Bild 1: Hinzufügen von Namespaces

System.IO

Danach stehen die Elemente dieses Namespaces in dem entsprechenden Fenster von LINQPad zur Verfügung.

Laufwerke

Das oberste Element der Hierarchie der Elemente des Dateisystems sind die Laufwerke. Diese können wir über die Funktion GetDrives auslesen und erhalten damit Objekte des Typs DriveInfo. Diese wiederum liefern einige Eigenschaften, mit denen wir die Informationen zum jeweiligen Laufwerk auslesen können.

Laufwerke ausgeben

Die Anweisungen, die wir ausprobieren wollen, fügen wir jeweils in die Sub Main-Prozedur ein. Wir steigen gleich ein und wollen alle Laufwerke des aktuellen Rechners im Direktfenster ausgeben. Dazu deklarieren wir zunächst ein Array namens objDrives und eine Variable namens objDrive, beide vom Typ DriveInfo. Es gibt kein Auflistungsobjekt, sondern eine Funktion namens GetDrives, die alle Laufwerke zurückliefert. Das Ergebnis, das wir zum Array objDrives hinzufügen, durchlaufen wir in einer For Each-Schleife. Dabei referenzieren wir das aktuelle Element jeweils mit der Variablen objDrive und geben den Wert seiner Eigenschaft Name aus:

Sub Main
     Dim objDrives() As DriveInfo
     Dim objDrive As DriveInfo
     objDrives = DriveInfo.GetDrives()
     For Each objDrive In objDrives
         Debug.print (objDrive.Name)
     Next objDrive    
End Sub 

Das Ergebnis sieht im Fall des hier verwendeten Rechners etwa wie in Bild 2 aus.

Ausgabe der Laufwerksnamen

Bild 2: Ausgabe der Laufwerksnamen

Eigenschaften von Laufwerken

Das DriveInfo-Objekt bietet eine ganze Reihe von Eigenschaften. Mit den folgenden Anweisungen geben wir diese im Direktbereich aus:

For Each objDrive In objDrives
     Debug.print (objDrive.Name)
     Debug.Print("AvailableFreeSpace: " & objDrive.AvailableFreeSpace.ToString())
     Debug.Print("DriveFormat:        " & objDrive.DriveFormat.ToString())
     Debug.Print("DriveType:          " & objDrive.DriveType.ToString())
     Debug.Print("IsReady:            " & objDrive.IsReady.ToString())
     Debug.Print("RootDirectory:      " & objDrive.RootDirectory.ToString())
     Debug.Print("TotalFreeSpace:     " & objDrive.TotalFreeSpace.ToString())
     Debug.Print("TotalSize:          " & objDrive.TotalSize.ToString())
     Debug.Print("VolumeLabel:        " & objDrive.VolumeLabel.ToString())
Next objDrive    

Die Eigenschaft IsReady ist beispielsweise interessant für CD/DVD-Laufwerke. Ist keine CD oder DVD eingelegt, liefert IsReady den Wert False. Ein Zugriff auf Eigenschaften wie AvailableFreeSpace oder DriveFormat ist somit nicht möglich, Name oder DriveType hingegen funktionieren. Um beim Zugriff auf alle Laufwerke Ausnahmen zu verhindern, können Sie prüfen, ob das Laufwerk bereit ist und nur dann auf die Eigenschaften zugreifen, die bei nicht bereiten Laufwerken nicht zur Verfügung stehen. Dazu verwenden wir eine einfache If…Then-Bedingung:

For Each objDrive In objDrives
     Debug.print(objDrive.Name)
     Debug.Print("DriveType:          " & objDrive.DriveType.ToString())
     Debug.Print("IsReady:            " & objDrive.IsReady.ToString())
     Debug.Print("RootDirectory:      " & objDrive.RootDirectory.ToString())
     If (objDrive.IsReady) Then
         Debug.Print("AvailableFreeSpace: " & objDrive.AvailableFreeSpace.ToString())
         Debug.Print("DriveFormat:        " & objDrive.DriveFormat.ToString())
         Debug.Print("TotalFreeSpace:     " & objDrive.TotalFreeSpace.ToString())
         Debug.Print("TotalSize:          " & objDrive.TotalSize.ToString())
         Debug.Print("VolumeLabel:        " & objDrive.VolumeLabel.ToString())
     End If
Next objDrive

Praktischerweise geben Eigenschaften wie etwa DriveFormat nicht wie unter VBA nur die Zahlenwerte von Konstanten aus, sondern über die Funktion ToString() auch direkt entsprechende Zeichenketten. Benötigen Sie einmal den Zahlenwert, können Sie ToString() einfach weglassen.

Auf ein Verzeichnis zugreifen

Auf ein Verzeichnis greifen wir über das DirectoryInfo-Objekt zu. Dieses erstellen wir jeweils mit der New-Methode und übergeben der Konstruktor-Methode dabei den Namen des Verzeichnisses. Hier geben wir direkt die Eigenschaften als Kommentar hinter der jeweiligen Anweisung an:

Dim objDirectoryInfo As DirectoryInfo
objDirectoryInfo = New DirectoryInfo("c:\Beispiele")
Debug.Print (objDirectoryInfo.CreationTime.ToString)    ''01.01.1601 01:00:00
Debug.Print (objDirectoryInfo.CreationTimeUtc)       ''01.01.1601
Debug.Print (objDirectoryInfo.Extension)                ''
Debug.Print (objDirectoryInfo.Exists)           ''False
Debug.Print (objDirectoryInfo.FullName)           ''c:\Beispiele
Debug.Print (objDirectoryInfo.Name)                    ''Beispiele
Debug.Print (objDirectoryInfo.Root.FullName)                ''c:\

Verzeichnisse eines Laufwerks lesen

Damit haben wir zwar schon einen Weg gefunden, auf ein Verzeichnis zuzugreifen, dessen Namen wir kennen. Aber wie können wir beispielsweise alle Verzeichnisse eines Laufwerks lesen und ausgeben Es sieht nicht so aus, als ob das DriveInfo-Objekte Eigenschaften bereitstellt, die eine Auflistung aller untergeordneten Verzeichnisse liefert. Aber wir kommen dennoch zum Ziel, denn das DirectoryInfo-Objekt bietet eine Funktion namens GetDirectories. Und da ein Laufwerk ja prinzipiell auch ein Verzeichnis abbilden, zum Beispiel c:\, können wir diese Funktion nutzen, um die Verzeichnisse eines Laufwerks zu ermitteln. Insgesamt sieht das etwa wie folgt aus:

Dim objDrive As DriveInfo
Dim objDirectoryDrive As DirectoryInfo
Dim objDirectory As DirectoryInfo
objDrive = New DriveInfo("c:")
objDirectoryDrive = New DirectoryInfo(objDrive.Name)
For Each objDirectory In objDirectoryDrive.GetDirectories
     Debug.Print(objDirectory.FullName)
Next objDirectory

Wir holen also das DriveInfo-Objekt und erstellen ein DirectoryInfo-Objekte mit dem Namen des DriveInfo-Objektes als Parameter. Dann durchlaufen wir diese Verzeichnisse in einer For Each-Schleife und geben mit der Eigenschaft FullName den Pfad der Verzeichnisse aus – zum Beispiel so:

c:\Dokumente und Einstellungen
c:\inetpub
c:\Intel
c:\MSOCache
...

Verzeichnisse suchen

Wir können der GetDirectories-Methode auch noch einen Suchbegriff als Parameter übergeben. Folgender Aufruf liefert alle Verzeichnisse, die mit Windows beginnen:

objDirectoryDrive.GetDirectories("Windows*")

Als Platzhalter können die von Access-SQL bekannten Platzhalter verwendet werden:

  • Sternchen (*): Platzhalter für beliebig viele beliebige Zeichen
  • Fragezeichen (): Platzhalter für ein beliebiges Zeichen

Und es gibt noch einen zweiten Parameter namens searchOption. Mit diesem können Sie festlegen, ob nur in der obersten Ebene gesucht werden soll oder rekursiv auch in den untergeordneten Verzeichnissen. Die Werte lauten:

  • AllDirectories (1): Alle Verzeichnisse inklusive Unterverzeichnisse durchsuchen
  • TopDirectoryOnly (0): Nur das aktuelle Verzeichnis durchsuchen

Wenn Sie den Parameterwert AllDirectories verwenden, kann es zu einem Fehler kommen, weil der Benutzer nicht ausreichende Berechtigungen für den Zugriff auf alle betroffenen Verzeichnisse hat. Der Aufruf für eine rekursive Suche sieht so aus:

objDirectoryDrive.GetDirectories("Windows*", searchOption.AllDirectories)

Besonderheit von DirectoryInfo: (Noch) nicht vorhandene Verzeichnisse

Das DirectoryInfo-Objekt hat eine Besonderheit, genauso wie das DriveInfo-Objekt und, wie wir weiter unten sehen werden, auch das FileInfo-Objekt. All diese Objekte können Sie mit der Angabe bestimmter Laufwerke, Verzeichnisse oder Dateien instanzieren, auch wenn die angegebenen Elemente noch gar nicht im Dateisystem vorhanden sind. Wir werden gleich als Beispiel für die Methoden von Verzeichnissen zeigen, wie Sie damit erst prüfen, ob ein Element bereits vorhanden ist und dieses gegebenenfalls erstellen können.

Methoden von Verzeichnissen

Das DirectoryInfo-Objekt als Repräsentant eines Verzeichnisses bietet eine ganze Reihe Methoden an, mit denen verschiedene Aufgaben rund um Verzeichnisse erledigt werden können – vom Erstellen über das Löschen und Verschieben bis hin zum Ermitteln der in einem Verzeichnis enthaltenen Daten:

  • Create: Erstellt das im DirectoryInfo angegebene Verzeichnis.
  • CreateSubdirectory: Erstellt ein Unterverzeichnis im Verzeichnis aus dem DirectoryInfo-Objekt.
  • Delete: Mit der Delete-Methode löschen Sie das Verzeichnis, das im DirectoryInfo-Objekt angegeben ist.
  • EnumerateDirectories: Liefert eine Auflistung der im referenzierten Verzeichnis enthaltenen Verzeichnisse als IEnumerable-Objekt.
  • EnumerateFiles: Liefert eine Auflistung der im referenzierten Verzeichnis enthaltenen Dateien als IEnumerable-Objekt.
  • EnumerateFileSystemInfos: Liefert eine Auflistung der im referenzierten Verzeichnis enthaltenen Verzeichnisse und Dateien gleichzeitig als IEnumerable-Objekt.
  • GetDirectories: Liefert alle Unterverzeichnisse des referenzierten Verzeichnisses als String-Array.
  • GetFiles: Liefert alle Dateien des referenzierten Verzeichnisses als String-Array.
  • GetFileSystemInfos: Liefert alle Unterverzeichnisse und Dateien des referenzierten Verzeichnisses als String-Array.
  • MoveTo: Verschiebt das referenzierte Verzeichnis in das als Parameter angegebene Verzeichnis.

Prüfen, ob ein Verzeichnis vorhanden ist

Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
Hier geht es zur Bestellung des Jahresabonnements des Magazins DATENBANKENTWICKLER:
Zur Bestellung ...
Danach greifen Sie sofort auf alle rund 200 Artikel unseres Angebots zu - auch auf diesen hier!
Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar