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).
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.
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.
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