Dateien mit VBA-Bordmitteln verwalten

Möchtest Du den gesamten Artikel lesen? Und vielleicht sogar den Artikel im PDF-Format und die Beispieldateien herunterladen? Dann hole Dir den Artikel gleich hier - völlig kostenlos!

Die Verwaltung von Dateien per Code ist öfter gefragt, als man denkt. Damit lassen sich Verzeichnisse erstellen, auslesen und entfernen, Dateien erstellen, löschen und bearbeiten und vieles mehr. Leider sind die Bordmitteln von VBA hier teilweise ein wenig sperrig. Allerdings sind sie für einfache Aufgaben durchaus ausreichend und erfordern nicht den Einsatz einer zusätzlichen Bibliothek wie der Scripting Runtime, wie es beispielsweise beim FileSystemObject der Fall ist. Also schauen wir uns in diesem Artikel einmal die Elemente von VBA an, mit denen wir auf die Elemente des Dateisystems zugreifen können und zeigen, was sich damit alles anstellen lässt. Schließlich schauen wir aber auch noch kritisch auf mögliche Nachteile.

Definitionen

In diesem Artikel werden wir die verschiedenen Elemente des Dateisystems benennen. Dabei wollen wir folgende Elemente definieren: Ein Pfad ist der gesamte Pfad von der Wurzel bis zum Dateinamen inklusive Dateiendung, also zum Beispiel c:\Verzeichnis1\Datei1.txt, oder bis zu einem Verzeichnis (c:\Verzeichnis1). Ein Verzeichnis ist das darin enthaltene Verzeichnis1. Eine Datei oder Dateiname ist Datei1.txt.

Die FileSystem-Klasse und Alternativen

Eine der bekanntesten Anweisungen zum Arbeiten mit dem Dateisystem ist vermutlich die Dir()-Funktion. Suchen wir im Objektkatalog nach dieser, finden wir schnell heraus, dass sie zu einer Klasse namens FileSystem gehört (siehe Bild 1).

Elemente der Klasse FileSystem im Objektkatalog

Bild 1: Elemente der Klasse FileSystem im Objektkatalog

Diese enthält noch einige weitere Elemente, von denen man vermutlich nicht alle auf dem Schirm hat.

In diesem Artikel werden wir uns diese im Detail ansehen und verschiedene praktische Lösungen zeigen, die sich damit realisieren lassen – ganz ohne weitere Bibliotheken.

Allerdings wollen wir alternative Möglichkeiten, die überdies in vielen Fällen leichter handzuhaben sind, nicht außen vor lassen. Deshalb gehen wir in einem weiteren Artikel beispielsweise auf das FileSystemObject ein, einer Klasse der Bibliothek Dateimanagement mit dem FileSystemObject verwalten (www.vbentwickler.de/455).

Übersicht über die Klasse FileSystem

Nun allerdings schauen wir uns erst einmal die grundlegenden Funktionen der verfügbaren Elemente zum Arbeiten mit Dateien und Verzeichnissen an.

Hier finden wir die folgenden Elemente:

  • ChDir: Ändert das aktuelle Arbeitsverzeichnis. Erwartet den einzustellenden Pfad als Parameter, zum Beispiel “C:\”.
  • ChDrive: Ändert das aktuelle Laufwerk. Erwartet das Ziellaufwerk als Parameter, zum Beispiel “C”.
  • CurDir: Gibt das aktuelle Arbeitsverzeichnis aus. Bei Office 365 wird hier standardmäßig das Verzeichnis C:\Users\[Benutzername]\AppData\Local\Temp ausgegeben.
  • CurDir$: Arbeitet wir CurDir, liefert jedoch das Ergebnis direkt als String zurück statt als Variant. Dies ist gegebenenfalls performanter, wenn das Ergebnis einer String-Variablen zugewiesen werden soll.
  • Dir: Sucht Dateien oder Verzeichnisse und gibt ihren Namen zurück. Der erste Parameter erwartet das zu untersuchende Verzeichnis oder die Datei und der zweite kann den Dateityp einschränken. Dir(“c:\”) liefert beispielsweise die erste Datei des Verzeichnisses c:\.
  • EOF: Abkürzung für End Of File. Erwartet die Angabe einer Dateinummer einer mit Open geöffneten Datei. Für diese Datei wird angegeben, ob beim Lesen das Ende der Datei erreicht wurde.
  • FileAttr: Gibt den Dateiattributwert für eine mit Open geöffnete Datei zurück. Erwartet die Dateinummer als ersten Parameter und den Zugriffsmodus als zweiten Parameter. Hier kommen die Werte 1 (Zugriffsmodus) und 2 (Dateizugriffsnummer) vor. 1 liefert also den Zugriffsmodus zurück, 2 die Dateizugriffsnummer.
  • FileCopy: Kopiert eine Datei von einem Ort zum anderen. Dabei wird als erster Parameter der Pfad zur Quelldatei angegeben und als zweiter Parameter der Pfad der zu erstellenden Datei.
  • FileDateTime: Gibt das Datum und die Uhrzeit der letzten Änderung einer Datei oder eines Verzeichnisses zurück. Als Parameter erwartet die Funktion den Pfad zu der zu untersuchenden Datei.
  • FileLen: Gibt die Größe einer Datei oder eines Verzeichnisses (immer 0) in Bytes zurück und erwartet den Pfad zu der zu untersuchenden Datei als Parameter.
  • FreeFile: Gibt eine verfügbare Dateinummer zurück, die wir mit der Open-Anweisung nutzen können, um eine Datei zu öffnen. Keine Parameter.
  • GetAttr: Liest die Attribute einer Datei oder eines Verzeichnisses aus.
  • Kill: Löscht die mit dem Parameter angegebene Datei.
  • Loc: Gibt die Position innerhalb einer mit Open geöffneten Datei aus.
  • LOF: Abkürzung für Length Of File. Liefert die Länge einer geöffneten Datei in Bytes. Erwartet die Dateinummer als Parameter.
  • MkDir: Erstellt ein Verzeichnis. Das Verzeichnis muss als Parameter angegeben werden. Das übergeordnete Verzeichnis muss bereits existieren.
  • Reset: Schließt alle mit Open geöffneten Dateien.
  • RmDir: Löscht ein Verzeichnis, sofern dieses leer ist. Erwartet den Pfad des zu löschenden Verzeichnisses.
  • Seek: Setzt die aktuelle Schreibposition innerhalt einer Datei oder gibt diese zurück. Der erste Parameter erwartet die Dateinummer. Wenn der zweite Parameter gesetzt ist, wird die Schreibposition an die angegebenen Position gesetzt. Ist der zweite Parameter leer, wird die Schreibposition zurückgegeben.
  • SetAttr: Setzt Attribute für eine Datei oder ein Verzeichnis. Der erste Parameter nimmt den Pfad der Datei oder des Verzeichnisses entgegen, der zweite den zu setzenden Wert für die Attribute. Es können nur die Attribute vbNormal, vbHidden oder vbReadOnly hinzugefügt oder entfernt werden.
  • Name: Ist keine Methode der Klasse FileSystem, aber wir gehen doch in diesem Artikel auf diese Anweisung ein, mit der man Dateien oder Verzeichnisse umbenennen kann.

Arbeitsverzeichnis wechseln

Mit der Funktion ChDir können wir das Arbeitsverzeichnis wechseln. Mit CurDir ermitteln wir das aktuelle Arbeitsverzeichnis.

Mit dem folgenden Beispiel lassen wir uns das Arbeitsverzeichnis vor der Änderung ausgeben, ändern es dann und geben dann das geänderte Arbeitsverzeichnis aus:

Public Sub Beispiel_ChDir()
     Debug.Print "Verzeichnis vorher: " & CurDir
     ChDir CurrentProject.Path
     Debug.Print "Verzeichnis nachner: " & CurDir
End Sub

Performanceunterschied CurDir und CurDir$

Um zu prüfen, wie sich die Performance bei den beiden Funktionen CurDir und CurDir$ verhält, haben wir die folgenden beiden Funktionen jeweils 10.000 Mal durchlaufen lassen:

Public Function CurDirVariant()
     Dim str As String
     str = CurDir
End Function
Public Function CurDirString()
     Dim str As String
     str = CurDir$
End Function

CurDir$ war dabei im Schnitt ca. 5% schneller als CurDir.

Zugriffsmodus einer Datei ermitteln

Wenn wir eine Datei mit Open geöffnet haben, können wir anschließend mit FileAttr prüfen, in welchem Zugriffsmodus sich die Datei befindet.

Im folgenden Beispiel öffnen wir eine bereits vorhandene Textdatei und lesen mit FileAttr(intFileNum, 1) den Zugriffsmodus aus:

Public Sub Dateizugriffsmodus()
     Dim intFileNum As Integer
     Dim intMode As Integer
     Dim strMode As String
     
     intFileNum = FreeFile
     Open CurrentProject.Path & "\Test.txt" _
         For Input As #intFileNum
     intMode = FileAttr(intFileNum, 1)
     Select Case intMode
         Case 1
             strMode = "Input (Lesemodus)"
         Case 2
             strMode = "Output (Schreibmodus)"
         Case 4
             strMode = "Random (Zufälliger Zugriff)"
         Case 8
             strMode = "Append (Anfügemodus)"
         Case 32
             strMode = "Binary (Binärmodus)"
     End Select
     Debug.Print "Datei ist im folgenden Modus geöffnet: " _
         & strMode
     Close #intFileNum
End Sub

Kopieren von Dateien

Um eine Datei von einem Ort zum anderen zu kopieren, verwenden wir die Anweisung FileCopy. Diese erwartet die beiden Parameter Quellpfad und Zielpfad.

Ein einfaches Beispiel kopiert die Datei Test.txt in eine neue Datei namens Text_Kopie.txt:

Public Sub DateienKopieren()
     Dim strQuelle As String
     Dim strZiel As String
     strQuelle = CurrentProject.Path & "\Test.txt"
     strZiel = CurrentProject.Path & "\Test_Kopie.txt"
     FileCopy strQuelle, strZiel
End Sub

Datum und Zeit der letzten Änderung einer Datei ermitteln

Das Datum der letzten Änderung können wir mit der Funktion FileDateTime ermitteln:

Public Sub Dateidatum()
     Dim strPfad As String
     strPfad = CurrentProject.Path & "\Test.txt"
     Debug.Print FileDateTime(strPfad)
End Sub

Das Ergebnis lautet beispielsweise:

08.01.2025 19:53:24

Größe einer Datei ermitteln

Mit der FileLen-Funktion ermitteln wir die Größe einer Datei in Byte:

Public Sub Dateigroesse()
     Dim strPfad As String
     strPfad = CurrentProject.Path & "\Test.txt"
     Debug.Print FileLen(strPfad)
End Sub

Dateinummer zum Öffnen einer Datei ermitteln

Mit der Funktion FreeFile erhalten wir eine Nummer zurück, die aktuell nicht in Zusammenhang mit einer geöffneten Datei in Verwendung ist, um eine aktuell geöffnete Datei zu referenzieren.

Im folgenden Beispiel schreiben wir die nächste freie Nummer in die Variable intFileNum, öffnen damit eine Datei, ermitteln dann mit FreeFile die nächste freie Nummer, schließen die Datei wieder und geben erneut das Ergebnis von FreeFile aus. Hier ist die Prozedur dazu:

Public Sub Dateinummer()
     Dim intFileNum As Integer
     
     intFileNum = FreeFile
     Debug.Print "Aktuelle Dateinummer: " & intFileNum
     
     Open CurrentProject.Path & "\Test.txt" _
         For Input As #intFileNum
     
     Debug.Print "Nächste Dateinummer: " & FreeFile
     Close #intFileNum
     
     Debug.Print "Nächste Dateinummer nach dem Schließen: _
         " & FreeFile
End Sub

Das Ergebnis sah so aus:

Aktuelle Dateinummer: 1
Nächste Dateinummer: 2
Nächste Dateinummer nach dem Schließen: 1

Ausführliche Beispiele für den Umgang mit Anweisungen wie Open, Close, Print et cetera beschreiben wir in einem eigenen Artikel namens VBA und Textdateien: Alles über Open, Close, Print und Co. (www.vbentwickler.de/454).

Alle Dateiattribute ausgeben

Mit der folgenden Prozedur nutzen wir die Funktion GetAttr, um den Zahlenwert auszugeben, der die Dateiattribute des angegebenen Pfades repräsentiert. Hier geben wir zunächst einmal eine Zeile im Direktbereich aus für jedes Attribut, das zutreffend ist.

Dazu vergleichen wir den jeweiligen Wert von lngAttribut über eine bitweise And-Operation mit dem jeweiligen Zahlenwert und geben einen Text aus, wenn das jeweilige Attribut zutreffend ist:

Public Sub AlleDateiattribute()
     Dim strPfad As String
     Dim lngAttribute As Long
     strPfad = CurrentProject.Path & "\Test.txt"
     lngAttribute = GetAttr(strPfad)
     If lngAttribute = 0 Then
         Debug.Print "vbNormal"
     End If
     If (lngAttribute And 1) = 1 Then
         Debug.Print "vbReadOnly"
     End If
     If (lngAttribute And 2) = 2 Then
         Debug.Print "vbHidden"
     End If
     If (lngAttribute And 4) = 4 Then
         Debug.Print "vbSystem"
     End If
     If (lngAttribute And 16) = 16 Then
         Debug.Print "vbDirectory"
     End If
     If (lngAttribute And 32) = 32 Then
         Debug.Print "vbArchive"
     End If
End Sub

Ermitteln, ob ein Pfad eine Datei oder ein Verzeichnis ist

Damit lässt sich dann beispielsweise herausfinden, ob ein Pfad eine Datei oder ein Verzeichnis ist.

Public Function IstDatei(strPfad As String) As Boolean
     Dim lngAttribute As Long
     lngAttribute = GetAttr(strPfad)
     If lngAttribute And vbDirectory = _
             vbDirectory Then
         IstDatei = True
     End If
End Function

Verzeichnis erstellen mit MkDir

Verzeichnisse erstellen wir mit der MkDir-Anweisung. Diese erwartet den Pfad des zu erstellenden Verzeichnisses. Wichtig ist hier, dass immer nur eine Verzeichnisebene mit einem Aufruf gleichzeitig hinzugefügt werden kann. Wir können also ausgehend von c:\ nur das Verzeichnis c:\Verzeichnis1 erstellen, aber nicht direkt c:\Verzeichnis1\Verzeichnis2.

Wenn wir ausgehend von c:\ das Verzeichnis c:\Verzeichnis1\Verzeichnis2 erstellen wollen, müssen wir in zwei Schritten vorgehen:

MkDir "c:\Verzeichnis1"
MkDir "c:\Verzeichnis1\Verzeichnis2"

Wenn wir direkt die zweite Anweisung aufrufen, ohne dass das Verzeichnis namens c:\Verzeichnis1 existiert, erhalten wir die Fehlermeldung aus Bild 2.

Fehler beim Versuch, ein Verzeichnis zu erstellen

Bild 2: Fehler beim Versuch, ein Verzeichnis zu erstellen

Mehrere Verzeichnisse gleichzeitig erstellen mit MkDir

Nachfolgend stellen wir eine Funktion vor, mit der wir nur mit der MkDir-Anweisung mehrere Verzeichnisse gleichzeitig erstellen können, in dem wir nur den zu erstellenden Pfad als Parameter übergeben.

Diese Funktion heißt VerzeichnisseErstellen und sieht wie in Listing 1 aus.

Public Function VerzeichnisErstellen(strPfad As String) As Boolean
     Dim strVerzeichnisse() As String
     Dim strAktuellerPfad As String
     Dim i As Integer
     strVerzeichnisse = Split(strPfad, "\")
     For i = LBound(strVerzeichnisse) To UBound(strVerzeichnisse)
         If Len(strAktuellerPfad) = 0 Then
             strAktuellerPfad = strVerzeichnisse(i)
         Else
             strAktuellerPfad = strAktuellerPfad & "\" & strVerzeichnisse(i)
             On Error Resume Next
             MkDir strAktuellerPfad
             On Error GoTo 0
         End If
         Debug.Print strVerzeichnisse(i), strAktuellerPfad
     Next i
     If Not Len(Dir(strPfad, vbDirectory)) = 0 Then
         VerzeichnisErstellen = True
     End If
End Function

Listing 1: Die Funktion VerzeichnisErstellen

Sie erwartet den Pfad des zu erstellenden Verzeichnisses (oder der Verzeichnisse) als Parameter.

Sie splittet zuerst den Pfad in ein Array auf, wobei das Backslash-Zeichen (\) als Trennzeichen verwendet wird. Wenn wir die Zeichenkette c:\Verzeichnis1\Verzeichnis2\Verzeichnis3 mit strPfad übergeben, enthält das Array also die folgenden Elemente:

  • c:
  • Verzeichnis1
  • Verzeichnis2
  • Verzeichnis3

In einer For…Next-Schleife über den kleinsten bis zum größten Indexwert des Arrays (in diesem Fall von 0 bis 3) prüfen wir, ob der Inhalt der Variablen strAktuellerPfad die Länge 0 aufweist.

In diesem Fall füllen wir strAktuellerPfad mit dem ersten Element des Arrays, hier c:.

In allen anderen Fällen, also für die Array-Elemente Verzeichnis1, Verzeichnis2 und Verzeichnis3, wird der Else-Teil der If…Then-Bedingung ausgeführt.

Hier wird der aktuelle Wert des Arrays getrennt durch einen Backslash an den Inhalt von strAktuellerPfad angehängt.

Im zweiten Durchlauf der Schleife bedeutet dies, das wir in strAktuellerPfad den Wert c:\Verzeichnis1 erhalten. Dieses Verzeichnis wollen wir nun zunächst mit MkDir anlegen.

Nun kann es sein, dass c:\Verzeichnis1 bereits existiert. Für diesen Fall deaktivieren wir die eingebaute Fehlerbehandlung zuvor mit On Error Resume Next.

Das Verzeichnis wird nun also angelegt, falls noch nicht vorhanden, oder eben nicht.

Auf die gleiche Weise fügen wir anschließend noch die weiteren Einträge des Arrays als Unterverzeichnisse hinzu, bis wir schließlich das Verzeichnis c:\Verzeichnis1\Verzeichnis2\Verzeichnis3 erhalten.

Nach dem Durchlaufen aller Elemente prüfen wir schließlich noch, ob das Verzeichnis existiert. Dazu nutzen wir die Dir()-Funktion, mit der wir prüfen, ob das mit strPfad angegebene Verzeichnis vorhanden ist.

Dir() liefert nicht nur Verzeichnisse

Man könnte meinen, dass eine Funktion namens Dir() dem Auslesen von Verzeichnissen dient.

Tatsächlich kann sie aber die Namen von Dateien und Verzeichnissen ermitteln. Aber von welchen Dateien und Verzeichnissen überhaupt?

Schauen wir uns einen einfachen Aufruf von Dir() ohne Parameter an – denn beide Parameter sind als optional gekennzeichnet. Dies liefert jedoch den Fehler aus Bild 3.

Fehler bei Versuch, Dir() ohne Parameter zu verwenden

Bild 3: Fehler bei Versuch, Dir() ohne Parameter zu verwenden

Dir() kann man zwar grundsätzlich ohne die Angabe von Parametern aufrufen, aber es muss zunächst initialisiert werden, indem man einen Wert für den ersten Parameter angibt.

Hier geben wir also nun beispielsweise c:\ an:

  Dir("c:\")

Damit liefert Dir() den Namen der ersten Datei des Verzeichnisses c:\. Das klappt auch für das aktuelle Datenbankverzeichnis, das wir mit CurrentProject.Path ermitteln:

Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

den kompletten Artikel im PDF-Format mit Beispieldatenbank

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar