{"id":55000453,"date":"2024-12-01T00:00:00","date_gmt":"2025-03-10T20:23:08","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=453"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Dateien_mit_VBABordmitteln_verwalten","status":"publish","type":"post","link":"https:\/\/vbentwickler.de\/Dateien_mit_VBABordmitteln_verwalten\/","title":{"rendered":"Dateien mit VBA-Bordmitteln verwalten"},"content":{"rendered":"<p><b>Die Verwaltung von Dateien per Code ist &ouml;fter gefragt, als man denkt. Damit lassen sich Verzeichnisse erstellen, auslesen und entfernen, Dateien erstellen, l&ouml;schen und bearbeiten und vieles mehr. Leider sind die Bordmitteln von VBA hier teilweise ein wenig sperrig. Allerdings sind sie f&uuml;r einfache Aufgaben durchaus ausreichend und erfordern nicht den Einsatz einer zus&auml;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&ouml;nnen und zeigen, was sich damit alles anstellen l&auml;sst. Schlie&szlig;lich schauen wir aber auch noch kritisch auf m&ouml;gliche Nachteile.<\/b><\/p>\n<h2>Definitionen<\/h2>\n<p>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 <b>c:\\Verzeichnis1\\Datei1.txt<\/b>, oder bis zu einem Verzeichnis (<b>c:\\Verzeichnis1<\/b>). Ein Verzeichnis ist das darin enthaltene <b>Verzeichnis1<\/b>. Eine Datei oder Dateiname ist <b>Datei1.txt<\/b>.<\/p>\n<h2>Die FileSystem-Klasse und Alternativen<\/h2>\n<p>Eine der bekanntesten Anweisungen zum Arbeiten mit dem Dateisystem ist vermutlich die <b>Dir()<\/b>-Funktion. Suchen wir im Objektkatalog nach dieser, finden wir schnell heraus, dass sie zu einer Klasse namens <b>FileSystem<\/b> geh&ouml;rt (siehe Bild 1).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_06\/pic_453_001.png\" alt=\"Elemente der Klasse FileSystem im Objektkatalog\" width=\"499,6267\" height=\"614,045\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Elemente der Klasse FileSystem im Objektkatalog<\/span><\/b><\/p>\n<p>Diese enth&auml;lt noch einige weitere Elemente, von denen man vermutlich nicht alle auf dem Schirm hat.<\/p>\n<p>In diesem Artikel werden wir uns diese im Detail ansehen und verschiedene praktische L&ouml;sungen zeigen, die sich damit realisieren lassen &#8211; ganz ohne weitere Bibliotheken.<\/p>\n<p>Allerdings wollen wir alternative M&ouml;glichkeiten, die &uuml;berdies in vielen F&auml;llen leichter handzuhaben sind, nicht au&szlig;en vor lassen. Deshalb gehen wir in einem weiteren Artikel beispielsweise auf das <b>FileSystemObject <\/b>ein, einer Klasse der Bibliothek <b>Dateimanagement mit dem FileSystemObject verwalten <\/b>(<b>www.vbentwickler.de\/455<\/b>).<\/p>\n<h2>&Uuml;bersicht &uuml;ber die Klasse FileSystem<\/h2>\n<p>Nun allerdings schauen wir uns erst einmal die grundlegenden Funktionen der verf&uuml;gbaren Elemente zum Arbeiten mit Dateien und Verzeichnissen an.<\/p>\n<p>Hier finden wir die folgenden Elemente:<\/p>\n<ul>\n<li><b>ChDir<\/b>: &Auml;ndert das aktuelle Arbeitsverzeichnis. Erwartet den einzustellenden Pfad als Parameter, zum Beispiel <b>&#8220;C:\\&#8221;<\/b>.<\/li>\n<li><b>ChDrive<\/b>: &Auml;ndert das aktuelle Laufwerk. Erwartet das Ziellaufwerk als Parameter, zum Beispiel <b>&#8220;C&#8221;<\/b>.<\/li>\n<li><b>CurDir<\/b>: Gibt das aktuelle Arbeitsverzeichnis aus. Bei Office 365 wird hier standardm&auml;&szlig;ig das Verzeichnis <b>C:\\Users\\[Benutzername]\\AppData\\Local\\Temp <\/b>ausgegeben.<\/li>\n<li><b>CurDir$<\/b>: Arbeitet wir <b>CurDir<\/b>, liefert jedoch das Ergebnis direkt als String zur&uuml;ck statt als Variant. Dies ist gegebenenfalls performanter, wenn das Ergebnis einer <b>String<\/b>-Variablen zugewiesen werden soll.<\/li>\n<li><b>Dir<\/b>: Sucht Dateien oder Verzeichnisse und gibt ihren Namen zur&uuml;ck. Der erste Parameter erwartet das zu untersuchende Verzeichnis oder die Datei und der zweite kann den Dateityp einschr&auml;nken. <b>Dir(&#8220;c:\\&#8221;) <\/b>liefert beispielsweise die erste Datei des Verzeichnisses <b>c:\\<\/b>.<\/li>\n<li><b>EOF<\/b>: Abk&uuml;rzung f&uuml;r <b>End Of File<\/b>. Erwartet die Angabe einer Dateinummer einer mit <b>Open <\/b>ge&ouml;ffneten Datei. F&uuml;r diese Datei wird angegeben, ob beim Lesen das Ende der Datei erreicht wurde.<\/li>\n<li><b>FileAttr<\/b>: Gibt den Dateiattributwert f&uuml;r eine mit Open ge&ouml;ffnete Datei zur&uuml;ck. Erwartet die Dateinummer als ersten Parameter und den Zugriffsmodus als zweiten Parameter. Hier kommen die Werte <b>1<\/b> (Zugriffsmodus) und <b>2 <\/b>(Dateizugriffsnummer) vor. <b>1 <\/b>liefert also den Zugriffsmodus zur&uuml;ck, <b>2 <\/b>die Dateizugriffsnummer.<\/li>\n<li><b>FileCopy<\/b>: 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.<\/li>\n<li><b>FileDateTime<\/b>: Gibt das Datum und die Uhrzeit der letzten &Auml;nderung einer Datei oder eines Verzeichnisses zur&uuml;ck. Als Parameter erwartet die Funktion den Pfad zu der zu untersuchenden Datei.<\/li>\n<li><b>FileLen<\/b>: Gibt die Gr&ouml;&szlig;e einer Datei oder eines Verzeichnisses (immer 0) in Bytes zur&uuml;ck und erwartet den Pfad zu der zu untersuchenden Datei als Parameter.<\/li>\n<li><b>FreeFile<\/b>: Gibt eine verf&uuml;gbare Dateinummer zur&uuml;ck, die wir mit der <b>Open<\/b>-Anweisung nutzen k&ouml;nnen, um eine Datei zu &ouml;ffnen. Keine Parameter.<\/li>\n<li><b>GetAttr<\/b>: Liest die Attribute einer Datei oder eines Verzeichnisses aus.<\/li>\n<li><b>Kill<\/b>: L&ouml;scht die mit dem Parameter angegebene Datei.<\/li>\n<li><b>Loc<\/b>: Gibt die Position innerhalb einer mit <b>Open <\/b>ge&ouml;ffneten Datei aus.<\/li>\n<li><b>LOF<\/b>: Abk&uuml;rzung f&uuml;r <b>Length Of File<\/b>. Liefert die L&auml;nge einer ge&ouml;ffneten Datei in Bytes. Erwartet die Dateinummer als Parameter.<\/li>\n<li><b>MkDir<\/b>: Erstellt ein Verzeichnis. Das Verzeichnis muss als Parameter angegeben werden. Das &uuml;bergeordnete Verzeichnis muss bereits existieren.<\/li>\n<li><b>Reset<\/b>: Schlie&szlig;t alle mit Open ge&ouml;ffneten Dateien.<\/li>\n<li><b>RmDir<\/b>: L&ouml;scht ein Verzeichnis, sofern dieses leer ist. Erwartet den Pfad des zu l&ouml;schenden Verzeichnisses.<\/li>\n<li><b>Seek<\/b>: Setzt die aktuelle Schreibposition innerhalt einer Datei oder gibt diese zur&uuml;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&uuml;ckgegeben.<\/li>\n<li><b>SetAttr<\/b>: Setzt Attribute f&uuml;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&uuml;r die Attribute. Es k&ouml;nnen nur die Attribute <b>vbNormal<\/b>, <b>vbHidden <\/b>oder <b>vbReadOnly <\/b>hinzugef&uuml;gt oder entfernt werden.<\/li>\n<li><b>Name<\/b>: Ist keine Methode der Klasse <b>FileSystem<\/b>, aber wir gehen doch in diesem Artikel auf diese Anweisung ein, mit der man Dateien oder Verzeichnisse umbenennen kann.<\/li>\n<\/ul>\n<h2>Arbeitsverzeichnis wechseln<\/h2>\n<p>Mit der Funktion <b>ChDir <\/b>k&ouml;nnen wir das Arbeitsverzeichnis wechseln. Mit <b>CurDir <\/b>ermitteln wir das aktuelle Arbeitsverzeichnis.<\/p>\n<p>Mit dem folgenden Beispiel lassen wir uns das Arbeitsverzeichnis vor der &Auml;nderung ausgeben, &auml;ndern es dann und geben dann das ge&auml;nderte Arbeitsverzeichnis aus:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>Beispiel_ChDir()\r\n     <span style=\"color:blue;\">Debug.Print<\/span> \"Verzeichnis vorher: \" & CurDir\r\n     ChDir CurrentProject.Path\r\n     <span style=\"color:blue;\">Debug.Print<\/span> \"Verzeichnis nachner: \" & CurDir\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Performanceunterschied CurDir und CurDir$<\/h2>\n<p>Um zu pr&uuml;fen, wie sich die Performance bei den beiden Funktionen <b>CurDir <\/b>und <b>CurDir$ <\/b>verh&auml;lt, haben wir die folgenden beiden Funktionen jeweils 10.000 Mal durchlaufen lassen:<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>CurDirVariant()\r\n     <span style=\"color:blue;\">Dim <\/span>str<span style=\"color:blue;\"> As String<\/span>\r\n     str = CurDir\r\n<span style=\"color:blue;\">End Function<\/span>\r\n<span style=\"color:blue;\">Public Function <\/span>CurDirString()\r\n     <span style=\"color:blue;\">Dim <\/span>str<span style=\"color:blue;\"> As String<\/span>\r\n     str = CurDir$\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b>CurDir$ <\/b>war dabei im Schnitt ca. 5% schneller als <b>CurDir<\/b>.<\/p>\n<h2>Zugriffsmodus einer Datei ermitteln<\/h2>\n<p>Wenn wir eine Datei mit Open ge&ouml;ffnet haben, k&ouml;nnen wir anschlie&szlig;end mit <b>FileAttr <\/b>pr&uuml;fen, in welchem Zugriffsmodus sich die Datei befindet.<\/p>\n<p>Im folgenden Beispiel &ouml;ffnen wir eine bereits vorhandene Textdatei und lesen mit <b>FileAttr(intFileNum, 1) <\/b>den Zugriffsmodus aus:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>Dateizugriffsmodus()\r\n     <span style=\"color:blue;\">Dim <\/span>intFileNum<span style=\"color:blue;\"> As Integer<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>intMode<span style=\"color:blue;\"> As Integer<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strMode<span style=\"color:blue;\"> As String<\/span>\r\n     \r\n     intFileNum = FreeFile\r\n     Open CurrentProject.Path & \"\\Test.txt\" _\r\n         For Input<span style=\"color:blue;\"> As <\/span>#intFileNum\r\n     intMode = FileAttr(intFileNum, 1)\r\n     Select Case intMode\r\n         <span style=\"color:blue;\">Case <\/span>1\r\n             strMode = \"Input (Lesemodus)\"\r\n         <span style=\"color:blue;\">Case <\/span>2\r\n             strMode = \"Output (Schreibmodus)\"\r\n         <span style=\"color:blue;\">Case <\/span>4\r\n             strMode = \"Random (Zuf&auml;lliger Zugriff)\"\r\n         <span style=\"color:blue;\">Case <\/span>8\r\n             strMode = \"Append (Anf&uuml;gemodus)\"\r\n         <span style=\"color:blue;\">Case <\/span>32\r\n             strMode = \"Binary (Bin&auml;rmodus)\"\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n     <span style=\"color:blue;\">Debug.Print<\/span> \"Datei ist im folgenden Modus ge&ouml;ffnet: \" _\r\n         & strMode\r\n     Close #intFileNum\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Kopieren von Dateien<\/h2>\n<p>Um eine Datei von einem Ort zum anderen zu kopieren, verwenden wir die Anweisung <b>FileCopy<\/b>. Diese erwartet die beiden Parameter Quellpfad und Zielpfad.<\/p>\n<p>Ein einfaches Beispiel kopiert die Datei <b>Test.txt <\/b>in eine neue Datei namens <b>Text_Kopie.txt<\/b>:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>DateienKopieren()\r\n     <span style=\"color:blue;\">Dim <\/span>strQuelle<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strZiel<span style=\"color:blue;\"> As String<\/span>\r\n     strQuelle = CurrentProject.Path & \"\\Test.txt\"\r\n     strZiel = CurrentProject.Path & \"\\Test_Kopie.txt\"\r\n     FileCopy strQuelle, strZiel\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Datum und Zeit der letzten &Auml;nderung einer Datei ermitteln<\/h2>\n<p>Das Datum der letzten &Auml;nderung k&ouml;nnen wir mit der Funktion <b>FileDateTime <\/b>ermitteln:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>Dateidatum()\r\n     <span style=\"color:blue;\">Dim <\/span>strPfad<span style=\"color:blue;\"> As String<\/span>\r\n     strPfad = CurrentProject.Path & \"\\Test.txt\"\r\n     <span style=\"color:blue;\">Debug.Print<\/span> FileDateTime(strPfad)\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Das Ergebnis lautet beispielsweise:<\/p>\n<pre>08.01.2025 19:53:24<\/pre>\n<h2>Gr&ouml;&szlig;e einer Datei ermitteln<\/h2>\n<p>Mit der <b>FileLen<\/b>-Funktion ermitteln wir die Gr&ouml;&szlig;e einer Datei in Byte:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>Dateigroesse()\r\n     <span style=\"color:blue;\">Dim <\/span>strPfad<span style=\"color:blue;\"> As String<\/span>\r\n     strPfad = CurrentProject.Path & \"\\Test.txt\"\r\n     <span style=\"color:blue;\">Debug.Print<\/span> File<span style=\"color:blue;\">Len<\/span>(strPfad)\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Dateinummer zum &Ouml;ffnen einer Datei ermitteln<\/h2>\n<p>Mit der Funktion <b>FreeFile <\/b>erhalten wir eine Nummer zur&uuml;ck, die aktuell nicht in Zusammenhang mit einer ge&ouml;ffneten Datei in Verwendung ist, um eine aktuell ge&ouml;ffnete Datei zu referenzieren.<\/p>\n<p>Im folgenden Beispiel schreiben wir die n&auml;chste freie Nummer in die Variable <b>intFileNum<\/b>, &ouml;ffnen damit eine Datei, ermitteln dann mit <b>FreeFile <\/b>die n&auml;chste freie Nummer, schlie&szlig;en die Datei wieder und geben erneut das Ergebnis von <b>FreeFile <\/b>aus. Hier ist die Prozedur dazu:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>Dateinummer()\r\n     <span style=\"color:blue;\">Dim <\/span>intFileNum<span style=\"color:blue;\"> As Integer<\/span>\r\n     \r\n     intFileNum = FreeFile\r\n     <span style=\"color:blue;\">Debug.Print<\/span> \"Aktuelle Dateinummer: \" & intFileNum\r\n     \r\n     Open CurrentProject.Path & \"\\Test.txt\" _\r\n         For Input<span style=\"color:blue;\"> As <\/span>#intFileNum\r\n     \r\n     <span style=\"color:blue;\">Debug.Print<\/span> \"N&auml;chste Dateinummer: \" & FreeFile\r\n     Close #intFileNum\r\n     \r\n     <span style=\"color:blue;\">Debug.Print<\/span> \"N&auml;chste Dateinummer nach dem Schlie&szlig;en: _\r\n         \" & FreeFile\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Das Ergebnis sah so aus:<\/p>\n<pre>Aktuelle Dateinummer: 1\r\nN&auml;chste Dateinummer: 2\r\nN&auml;chste Dateinummer nach dem Schlie&szlig;en: 1<\/pre>\n<p>Ausf&uuml;hrliche Beispiele f&uuml;r den Umgang mit Anweisungen wie Open, Close, Print et cetera beschreiben wir in einem eigenen Artikel namens <b>VBA und Textdateien: Alles &uuml;ber Open, Close, Print und Co. <\/b>(<b>www.vbentwickler.de\/454<\/b>).<\/p>\n<h2>Alle Dateiattribute ausgeben<\/h2>\n<p>Mit der folgenden Prozedur nutzen wir die Funktion <b>GetAttr<\/b>, um den Zahlenwert auszugeben, der die Dateiattribute des angegebenen Pfades repr&auml;sentiert. Hier geben wir zun&auml;chst einmal eine Zeile im Direktbereich aus f&uuml;r jedes Attribut, das zutreffend ist.<\/p>\n<p>Dazu vergleichen wir den jeweiligen Wert von lngAttribut &uuml;ber eine bitweise <b>And<\/b>-Operation mit dem jeweiligen Zahlenwert und geben einen Text aus, wenn das jeweilige Attribut zutreffend ist:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>AlleDateiattribute()\r\n     <span style=\"color:blue;\">Dim <\/span>strPfad<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngAttribute<span style=\"color:blue;\"> As Long<\/span>\r\n     strPfad = CurrentProject.Path & \"\\Test.txt\"\r\n     lngAttribute = GetAttr(strPfad)\r\n     <span style=\"color:blue;\">If <\/span>lngAttribute = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">Debug.Print<\/span> \"vbNormal\"\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span>(lngAttribute And 1) = 1<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">Debug.Print<\/span> \"vbReadOnly\"\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span>(lngAttribute And 2) = 2<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">Debug.Print<\/span> \"vbHidden\"\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span>(lngAttribute And 4) = 4<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">Debug.Print<\/span> \"vbSystem\"\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span>(lngAttribute And 16) = 16<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">Debug.Print<\/span> \"vbDirectory\"\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span>(lngAttribute And 32) = 32<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">Debug.Print<\/span> \"vbArchive\"\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Ermitteln, ob ein Pfad eine Datei oder ein Verzeichnis ist<\/h2>\n<p>Damit l&auml;sst sich dann beispielsweise herausfinden, ob ein Pfad eine Datei oder ein Verzeichnis ist. <\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>IstDatei(strPfad<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngAttribute<span style=\"color:blue;\"> As Long<\/span>\r\n     lngAttribute = GetAttr(strPfad)\r\n     If lngAttribute And vbDirectory = _\r\n             vbDirectory Then\r\n         IstDatei = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<h2>Verzeichnis erstellen mit MkDir<\/h2>\n<p>Verzeichnisse erstellen wir mit der <b>MkDir<\/b>-Anweisung. Diese erwartet den Pfad des zu erstellenden Verzeichnisses. Wichtig ist hier, dass immer nur eine Verzeichnisebene mit einem Aufruf gleichzeitig hinzugef&uuml;gt werden kann. Wir k&ouml;nnen also ausgehend von <b>c:\\ <\/b>nur das Verzeichnis <b>c:\\Verzeichnis1 <\/b>erstellen, aber nicht direkt <b>c:\\Verzeichnis1\\Verzeichnis2<\/b>.<\/p>\n<p>Wenn wir ausgehend von <b>c:\\ <\/b>das Verzeichnis <b>c:\\Verzeichnis1\\Verzeichnis2 <\/b>erstellen wollen, m&uuml;ssen wir in zwei Schritten vorgehen:<\/p>\n<pre>MkDir \"c:\\Verzeichnis1\"\r\nMkDir \"c:\\Verzeichnis1\\Verzeichnis2\"<\/pre>\n<p>Wenn wir direkt die zweite Anweisung aufrufen, ohne dass das Verzeichnis namens <b>c:\\Verzeichnis1<\/b> existiert, erhalten wir die Fehlermeldung aus Bild 2.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_06\/pic_453_002.png\" alt=\"Fehler beim Versuch, ein Verzeichnis zu erstellen\" width=\"549,6265\" height=\"200,9829\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Fehler beim Versuch, ein Verzeichnis zu erstellen<\/span><\/b><\/p>\n<h2>Mehrere Verzeichnisse gleichzeitig erstellen mit MkDir<\/h2>\n<p>Nachfolgend stellen wir eine Funktion vor, mit der wir nur mit der <b>MkDir<\/b>-Anweisung mehrere Verzeichnisse gleichzeitig erstellen k&ouml;nnen, in dem wir nur den zu erstellenden Pfad als Parameter &uuml;bergeben.<\/p>\n<p>Diese Funktion hei&szlig;t <b>VerzeichnisseErstellen<\/b> und sieht wie in Listing 1 aus.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>VerzeichnisErstellen(strPfad<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strVerzeichnisse()<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strAktuellerPfad<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>i<span style=\"color:blue;\"> As Integer<\/span>\r\n     strVerzeichnisse = <span style=\"color:blue;\">Split<\/span>(strPfad, \"\\\")\r\n     For i = <span style=\"color:blue;\">LBound<\/span>(strVerzeichnisse) To <span style=\"color:blue;\">UBound<\/span>(strVerzeichnisse)\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(strAktuellerPfad) = 0<span style=\"color:blue;\"> Then<\/span>\r\n             strAktuellerPfad = strVerzeichnisse(i)\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             strAktuellerPfad = strAktuellerPfad & \"\\\" & strVerzeichnisse(i)\r\n             On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n             MkDir strAktuellerPfad\r\n             <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">Debug.Print<\/span> strVerzeichnisse(i), strAktuellerPfad\r\n     <span style=\"color:blue;\">Next<\/span> i\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(Dir(strPfad, vbDirectory)) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         VerzeichnisErstellen = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Die Funktion VerzeichnisErstellen<\/span><\/b><\/p>\n<p>Sie erwartet den Pfad des zu erstellenden Verzeichnisses (oder der Verzeichnisse) als Parameter.<\/p>\n<p>Sie splittet zuerst den Pfad in ein Array auf, wobei das Backslash-Zeichen (<b>\\<\/b>) als Trennzeichen verwendet wird. Wenn wir die Zeichenkette <b>c:\\Verzeichnis1\\Verzeichnis2\\Verzeichnis3 <\/b>mit <b>strPfad <\/b>&uuml;bergeben, enth&auml;lt das Array also die folgenden Elemente:<\/p>\n<ul>\n<li><b>c:<\/b><\/li>\n<li><b>Verzeichnis1<\/b><\/li>\n<li><b>Verzeichnis2<\/b><\/li>\n<li><b>Verzeichnis3<\/b><\/li>\n<\/ul>\n<p>In einer <b>For&#8230;Next<\/b>-Schleife &uuml;ber den kleinsten bis zum gr&ouml;&szlig;ten Indexwert des Arrays (in diesem Fall von <b>0 <\/b>bis <b>3<\/b>) pr&uuml;fen wir, ob der Inhalt der Variablen <b>strAktuellerPfad <\/b>die L&auml;nge <b>0 <\/b>aufweist.<\/p>\n<p>In diesem Fall f&uuml;llen wir <b>strAktuellerPfad <\/b>mit dem ersten Element des Arrays, hier <b>c:<\/b>.<\/p>\n<p>In allen anderen F&auml;llen, also f&uuml;r die Array-Elemente <b>Verzeichnis1<\/b>, <b>Verzeichnis2 <\/b>und <b>Verzeichnis3<\/b>, wird der <b>Else<\/b>-Teil der <b>If&#8230;Then<\/b>-Bedingung ausgef&uuml;hrt.<\/p>\n<p>Hier wird der aktuelle Wert des Arrays getrennt durch einen Backslash an den Inhalt von <b>strAktuellerPfad <\/b>angeh&auml;ngt.<\/p>\n<p>Im zweiten Durchlauf der Schleife bedeutet dies, das wir in <b>strAktuellerPfad <\/b>den Wert <b>c:\\Verzeichnis1 <\/b>erhalten. Dieses Verzeichnis wollen wir nun zun&auml;chst mit <b>MkDir <\/b>anlegen.<\/p>\n<p>Nun kann es sein, dass <b>c:\\Verzeichnis1 <\/b>bereits existiert. F&uuml;r diesen Fall deaktivieren wir die eingebaute Fehlerbehandlung zuvor mit <b>On Error Resume Next<\/b>.<\/p>\n<p>Das Verzeichnis wird nun also angelegt, falls noch nicht vorhanden, oder eben nicht.<\/p>\n<p>Auf die gleiche Weise f&uuml;gen wir anschlie&szlig;end noch die weiteren Eintr&auml;ge des Arrays als Unterverzeichnisse hinzu, bis wir schlie&szlig;lich das Verzeichnis <b>c:\\Verzeichnis1\\Verzeichnis2\\Verzeichnis3 <\/b>erhalten.<\/p>\n<p>Nach dem Durchlaufen aller Elemente pr&uuml;fen wir schlie&szlig;lich noch, ob das Verzeichnis existiert. Dazu nutzen wir die <b>Dir()<\/b>-Funktion, mit der wir pr&uuml;fen, ob das mit <b>strPfad <\/b>angegebene Verzeichnis vorhanden ist.<\/p>\n<h2>Dir() liefert nicht nur Verzeichnisse<\/h2>\n<p>Man k&ouml;nnte meinen, dass eine Funktion namens <b>Dir() <\/b>dem Auslesen von Verzeichnissen dient.<\/p>\n<p>Tats&auml;chlich kann sie aber die Namen von Dateien und Verzeichnissen ermitteln. Aber von welchen Dateien und Verzeichnissen &uuml;berhaupt?<\/p>\n<p>Schauen wir uns einen einfachen Aufruf von <b>Dir() <\/b>ohne Parameter an &#8211; denn beide Parameter sind als optional gekennzeichnet. Dies liefert jedoch den Fehler aus Bild 3.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_06\/pic_453_003.png\" alt=\"Fehler bei Versuch, Dir() ohne Parameter zu verwenden\" width=\"549,6265\" height=\"245,1184\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Fehler bei Versuch, Dir() ohne Parameter zu verwenden<\/span><\/b><\/p>\n<p><b>Dir() <\/b>kann man zwar grunds&auml;tzlich ohne die Angabe von Parametern aufrufen, aber es muss zun&auml;chst initialisiert werden, indem man einen Wert f&uuml;r den ersten Parameter angibt.<\/p>\n<p>Hier geben wir also nun beispielsweise <b>c:\\<\/b> an:<\/p>\n<pre>  Dir(\"c:\\\")<\/pre>\n<p>Damit liefert <b>Dir() <\/b>den Namen der ersten Datei des Verzeichnisses <b>c:\\<\/b>. Das klappt auch f&uuml;r das aktuelle Datenbankverzeichnis, das wir mit <b>CurrentProject.Path <\/b>ermitteln:<\/p>\n<pre>  Dir(CurrentProject.Path & \"\\\")\r\nDateimanagementMitVBABordmitteln.accdb<\/pre>\n<p>Um die Elemente eines Verzeichnisses zu erhalten, m&uuml;ssen wir immer ein abschlie&szlig;endes Backslash-Zeichen (<b>\\<\/b>) anh&auml;ngen. Ohne dieses liefert der Aufruf eine leere Zeichenkette. Es gibt ein Beispiel, in dem das sinnvoll ist &#8211; mehr dazu weiter unten.<\/p>\n<h2>Alle Dateien eines Verzeichnisses durchlaufen<\/h2>\n<p>Nun wissen wir, wie wir an die erste Datei eines Verzeichnisses gelangen. Wie aber kommen wir an die &uuml;brigen Dateien?<\/p>\n<p>Hier kommt der Aufruf der <b>Dir()<\/b>-Funktion ohne Parameter zum Zuge. Sobald wir <b>Dir() <\/b>einmal mit einem Pfad aufgerufen haben, bleibt dieser Pfad intern f&uuml;r weitere Aufrufe gespeichert &#8211; bis man <b>Dir() <\/b>mit einem anderen Pfad aufruft.<\/p>\n<p>Wenn wir <b>Dir() <\/b>mit Pfadangabe aufgerufen haben, erhalten wir die erste Datei dieses Verzeichnispfades zur&uuml;ck. Wenn wir die n&auml;chste Datei ermitteln wollen, rufen wir <b>Dir() <\/b>einfach ohne Pfadangabe auf, also ohne Angabe des ersten Parameters.<\/p>\n<p>Und wenn wir alle Dateien eines Verzeichnisses ausgeben wollen, verwenden wir die folgende Prozedur.<\/p>\n<p>Diese ermittelt die erste Datei des Verzeichnisses, das wir mit <b>CurrentProject.Path &#038; &#8220;\\&#8221; <\/b>ermitteln, und schreibt diese in die Variable <b>strDatei<\/b>.<\/p>\n<p>Dann steigen wir in eine <b>Do While<\/b>-Schleife ein, aber nur, wenn <b>strDatei <\/b>nicht leer ist, also die L&auml;nge der enthaltenen Zeichenkette nicht <b>0 <\/b>ist.<\/p>\n<p>Innerhalb der Schleife geben wir den aktuellen Wert von <b>strDatei <\/b>aus und rufen <b>Dir() <\/b>ohne Parameter auf, um den n&auml;chsten Dateinamen einzulesen. Dieser wird dann bei n&auml;chsten Schleifendurchlauf ausgegeben und so weiter &#8211; bis die <b>Dir()<\/b>-Funktion keinen weiteren Dateinamen mehr findet und <b>strDatei <\/b>leer bleibt:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>AlleDateienEinesVerzeichnisses()\r\n     <span style=\"color:blue;\">Dim <\/span>strPfad<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strDatei<span style=\"color:blue;\"> As String<\/span>\r\n     strPfad = CurrentProject.Path & \"\\\"\r\n     strDatei = Dir(strPfad)\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(strDatei) = 0\r\n         <span style=\"color:blue;\">Debug.Print<\/span> strDatei\r\n         strDatei = Dir()\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Unerwartete Effekte<\/h2>\n<p>Das die <b>Dir()<\/b>-Funktion so arbeitet, hat nicht nur Vorteile. Wir sollten n&auml;mlich darauf achten, dass wir diese nicht in verschachtelten Routinen einsetzen &#8211; also beispielsweise in einer Prozedur, die wir innerhalb der <b>Do While<\/b>-Schleife des vorherigen Beispiels aufrufen und die ihrerseits die <b>Dir()<\/b>-Funktion f&uuml;r irgendeinen Zweck verwendet.<\/p>\n<p>Wenn wir in einer untergeordneten Prozedur n&auml;mlich <b>Dir() <\/b>mit einem anderen Pfad aufrufen und anschlie&szlig;end wieder zur urspr&uuml;nglichen Routine zur&uuml;ckkehren, wird diese die <b>Dir()<\/b>-Funktion auch mit dem Pfad im Hinterkopf aufrufen, den wir in der untergeordneten Prozedur genutzt haben.<\/p>\n<p>Wenn sich ein solches Konstrukt nicht verhindern l&auml;sst, ist die beste L&ouml;sung der Einsatz der Techniken, die wir im Artikel <b> Dateimanagement mit dem FileSystemObject<\/b> (<b>www.vbentwickler.de\/455<\/b>) vorstellen.<\/p>\n<h2>Dateien nach einem bestimmten Schema ermitteln<\/h2>\n<p>Mit <b>Dir() <\/b>k&ouml;nnen wir nicht nur nach allen Dateien eines Verzeichnisses suchen, sondern auch nach solchen mit einem bestimmten Schema im Dateinamen.<\/p>\n<p>Wir k&ouml;nnen beispielsweise gezielt nach einer bestimmten Datei suchen:<\/p>\n<pre>  Dir(CurrentProject.Path & \"\\pic001.png\")\r\npic001.png<\/pre>\n<p>Wird die Datei im angegebenen Verzeichnis gefunden, wird der Name der Datei zur&uuml;ckgeliefert.<\/p>\n<h2>Dateien mit einer bestimmten Dateiendung ermitteln<\/h2>\n<p>Wir k&ouml;nnen auch nach allen Dateien mit einer bestimmten Dateiendung suchen &#8211; zum Beispiel solche mit der Endung <b>.png<\/b>.<\/p>\n<p>Dazu passen wir lediglich den initialen Pfad f&uuml;r den Aufruf der <b>Dir()<\/b>-Funktion an:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>AllePNGDateienEinesVerzeichnisses()\r\n     <span style=\"color:blue;\">Dim <\/span>strPfad<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strDatei<span style=\"color:blue;\"> As String<\/span>\r\n     strPfad = CurrentProject.Path & \"\\*.png\"\r\n     strDatei = Dir(strPfad)\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(strDatei) = 0\r\n         <span style=\"color:blue;\">Debug.Print<\/span> strDatei\r\n         strDatei = Dir()\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Auf die gleiche Weise k&ouml;nnen wir auch nach beliebigen anderen Dateien suchen. Dabei k&ouml;nnen wir die folgenden Platzhalter verwenden:<\/p>\n<ul>\n<li><b>*<\/b>: Steht f&uuml;r kein, ein oder mehrere viele beliebige Zeichen.<\/li>\n<li><b>?<\/b>: Steht f&uuml;r ein beliebiges Zeichen.<\/li>\n<\/ul>\n<h2>Dir() ohne abschlie&szlig;endes Backslash zum Ermitteln des aktuellen Verzeichnisses<\/h2>\n<p>Wie oben erw&auml;hnt, gibt es einen sinnvollen Einsatzzweck f&uuml;r die <b>Dir()<\/b>-Funktion, wenn man keinen abschlie&szlig;enden Backslash angibt. Dieser ergibt sich, wenn wir als zweiten Parameter <b>vbDirectory <\/b>angeben. Dann erhalten wir n&auml;mlich den Namen des Verzeichnisses des angegebenen Pfades:<\/p>\n<pre>  Dir(\"c:\\Verzeichnis1\\Verzeichnis2\", vbDirectory)\r\nVerzeichnis2<\/pre>\n<h2>Weitere M&ouml;glichkeiten von Dir() &uuml;ber den zweiten Parameter<\/h2>\n<p>Die <b>Dir()<\/b>-Funktion liefert auch noch einen zweiten Parameter.<\/p>\n<p>Dieser kann die folgenden Werte annehmen:<\/p>\n<ul>\n<li><b>vbArchive<\/b> (32): Wird automatisch beim Erstellen oder &Auml;ndern einer Datei gesetzt und markiert eine Datei als &#8220;zu archivieren&#8221;.<\/li>\n<li><b>vbDirectory<\/b> (16): Ber&uuml;cksichtigt Verzeichnisse als Suchergebnis.<\/li>\n<li><b>vbHidden<\/b> (2): Bezieht sich auf versteckte Dateien.<\/li>\n<li><b>vbNormal<\/b> (0): Keine Attribute.<\/li>\n<li><b>vbReadOnly<\/b> (1): Bezieht sich nur auf schreibgesch&uuml;tzte Dateien.<\/li>\n<li><b>vbSystem<\/b> (4): Ber&uuml;cksichtigt nur Systemdateien.<\/li>\n<li><b>vbVolume<\/b> (8): Ber&uuml;cksichtigt nur Laufwerke.<\/li>\n<\/ul>\n<p>Verschiedene Attribute k&ouml;nnen mit dem <b>Or<\/b>-Operator verkn&uuml;pft werden. Wenn wir beispielsweise nach Dateien suchen wollen, die versteckt und schreibgesch&uuml;tzt sind, verwenden wir als zweiten Parameter den Wert <b>vbHidden Or vbReadOnly<\/b>.<\/p>\n<h2>Dateien mit vbArchiv-Markierung<\/h2>\n<p>Beim Erstellen oder &Auml;ndern einer Datei setzt Windows automatisch eine Markierung. Dies ist eine Unters&uuml;tzung f&uuml;r Backup-Programme.<\/p>\n<p>Backup-Programme k&ouml;nnen f&uuml;r Dateien, die gesichert wurden, diese Markierung entfernen.<\/p>\n<p>Sie wird erst wieder gesetzt, wenn die Datei das n&auml;chste Mal ge&auml;ndert wird. So kann das Backup-Programm beim Anfertigen eines Backups erkennen, ob eine Datei seit der letzten Sicherung ge&auml;ndert wurde und braucht diese gegebenenfalls nicht erneut zu sichern.<\/p>\n<p>Diese Eigenschaft kann man sich zunutze machen, wenn man selbst Dateien sichern m&ouml;chte. Wenn man die Markierung dann entfernen will, kann man das mit <b>SetAttr <\/b>erledigen (siehe unten).<\/p>\n<p>Mit <b>GetAttr<\/b> kann man dann auslesen, ob das <b>vbArchiv<\/b>-Attribut gesetzt ist und diese Datei dann sichern.<\/p>\n<h2>Verzeichnisse mit Dir() ermitteln<\/h2>\n<p>Wenn wir als zweiten Parameter der <b>Dir()<\/b>-Funktion den Wert <b>vbDirectory <\/b>angeben, liefert diese statt Dateinamen die Namen von Verzeichnissen zur&uuml;ck.<\/p>\n<p>Die folgende Anweisung gibt das erste Verzeichnis des angegebenen Verzeichnisses aus:<\/p>\n<pre>  Dir(CurrentProject.Path, vbDirectory)<\/pre>\n<p>Wenn wir alle Verzeichnisse ausgeben wollen, k&ouml;nnen wir das wieder in einer <b>Do While<\/b>-Schleife erledigen:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>AlleUnterverzeichnisseEinesVerzeichnisses()\r\n     <span style=\"color:blue;\">Dim <\/span>strPfad<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strDatei<span style=\"color:blue;\"> As String<\/span>\r\n     strPfad = CurrentProject.Path & \"\\\"\r\n     strDatei = Dir(strPfad, vbDirectory)\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(strDatei) = 0\r\n         <span style=\"color:blue;\">Debug.Print<\/span> strDatei\r\n         strDatei = Dir()\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Volume-Bezeichnung mit Dir() ermitteln<\/h2>\n<p>Wir k&ouml;nnen in den Eigenschaften eines Laufwerks eine Bezeichnung f&uuml;r das Laufwerk definieren (siehe Bild 4).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_06\/pic_453_004.png\" alt=\"Festlegen einer Volume-Bezeichnung\" width=\"424,6267\" height=\"583,7155\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Festlegen einer Volume-Bezeichnung<\/span><\/b><\/p>\n<p>Diese Bezeichnung k&ouml;nnen wir ermitteln, wenn wir die <b>Dir()<\/b>-Funktion mit dem Wert <b>vbVolume <\/b>als zweiten Parameter aufrufen:<\/p>\n<pre>  Dir(Currentproject.path, vbVolume)\r\nHauptlaufwerk<\/pre>\n<h2>Pr&uuml;fen, ob ein Verzeichnis existiert<\/h2>\n<p>Ob ein Verzeichnis existiert, k&ouml;nnen wir mit der <b>Dir()<\/b>-Funktion herausfinden. Diese bietet als zweiten Parameter unter anderem das Attribut <b>vbDirectory <\/b>an. Wenn wir dieses als Parameter angeben und als ersten Parameter einen Pfad zu einem Verzeichnis &uuml;bergeben, erhalten wir den Namen des letzten Verzeichnisses des Pfades als Ergebnis. Diesen m&uuml;ssen wir dann noch mit dem letzten Verzeichnis des Pfades vergleichen.<\/p>\n<p>Wir haben beispielsweise den folgenden Pfad angelegt:<\/p>\n<pre>c:\\Verzeichnis1\\Verzeichnis2\\Verzeichnis3<\/pre>\n<p>Wir sollen nun herausfinden, ob dieser Pfad bis zu dem Verzeichnis <b>Verzeichnis5 <\/b>existiert. Dazu rufen wir zun&auml;chst die <b>Dir()<\/b>-Funktion mit diesem Pfad als ersten und <b>vbDirectory <\/b>als zweiten Parameter auf:<\/p>\n<pre><span style=\"color:blue;\">Debug.Print<\/span> Dir(\"c:\\Verzeichnis1\\Verzeichnis2\\Verzeichnis3\", vbDirectory)<\/pre>\n<p>Damit erhalten wir folgendes Ergebnis:<\/p>\n<pre>Verzeichnis3<\/pre>\n<p><b>Dir()<\/b> liefert mit dem Wert <b>vbDirectory <\/b>f&uuml;r den zweiten Parameter also den Namen des letzten Verzeichnisses des &uuml;bergebenen Pfades. Diesen m&uuml;ssen wir dann noch abgleichen. Das erledigen wir mit der folgenden Funktion:<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>VerzeichnisVorhanden(strPfad<span style=\"color:blue;\"> As String<\/span>) _\r\n       <span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strVerzeichnis<span style=\"color:blue;\"> As String<\/span>\r\n     strVerzeichnis = Dir(strPfad, vbDirectory)\r\n     If <span style=\"color:blue;\">Right<\/span>(strPfad, <span style=\"color:blue;\">Len<\/span>(strVerzeichnis)) = _\r\n             strVerzeichnis Then\r\n         VerzeichnisVorhanden = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p>Die Funktion liest zun&auml;chst das letzte Verzeichnis aus und schreibt es in <b>strVerzeichnis<\/b>. Dann pr&uuml;ft es, ob die letzten <b>x <\/b>Zeichen des Pfades aus <b>strPfad <\/b>mit dem Inhalt von <b>strVerzeichnis <\/b>&uuml;bereinstimmen. <b>x <\/b>ist dabei die L&auml;nge der Zeichenkette aus <b>strVerzeichnis<\/b>. Falls ja, liefert die Funktion das Ergebnis <b>True <\/b>zur&uuml;ck.<\/p>\n<h2>Verzeichnis l&ouml;schen mit RmDir<\/h2>\n<p>Ein leeres Verzeichnis k&ouml;nnen wir ganz einfach mit der Anweisung <b>RmDir <\/b>l&ouml;schen. Dazu &uuml;bergeben wir der Anweisung den Pfad des zu l&ouml;schenden Verzeichnisses, beispielsweise so:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>strPfad<span style=\"color:blue;\"> As String<\/span>\r\nstrPfad = CurrentProject.Path & \"\\Verzeichnis1\"\r\nRmDir strPfad<\/pre>\n<h2>Verzeichnis mit Inhalt l&ouml;schen mit RmDir<\/h2>\n<p>Hier liefert <b>RmDir <\/b>jedoch bereits einen Fehler, wenn das zu l&ouml;schende Verzeichnis ein Unterverzeichnis oder eine Datei enth&auml;lt. Wir m&uuml;ssen also erst die enthaltenen Unterverzeichnisse und Dateien l&ouml;schen.<\/p>\n<p>Dabei m&uuml;ssten wir uns jedoch mit rekursiven Funktionen helfen, die wiederum die <b>Dir()<\/b>-Funktion verwenden.<\/p>\n<p>Hier schl&auml;gt dann das Problem durch, dass die <b>Dir()<\/b>-Funktion sich immer die zuletzt verwendete Pfadangabe merkt und die aufrufende Instanz der rekursiven Funktion fr&uuml;her oder sp&auml;ter nicht mit dem eigenen Verzeichnis fortf&auml;hrt, sondern mit dem der aufgerufenen Instanz der rekursiven Funktion. Die Beschreibung einer Funktion, die dennoch funktioniert, w&uuml;rde an dieser Stelle den Rahmen sprengen.<\/p>\n<h2>Attribute setzen mit SetAttr<\/h2>\n<p>Mit <b>SetAttr <\/b>k&ouml;nnen wir einige der verf&uuml;gbaren Attribute f&uuml;r Dateien und Verzeichnisse setzen, aber nicht alle, die wir mit <b>GetAttr <\/b>auslesen k&ouml;nnen. Wir k&ouml;nnen beispielsweise das Attribut <b>vbDirectory <\/b>nicht von einem Verzeichnis entfernen und nicht f&uuml;r eine Datei hinzuf&uuml;gen. Alle anderen k&ouml;nnen wir jedoch setzen:<\/p>\n<ul>\n<li><b>vbReadOnly <\/b>(1)<\/li>\n<li><b>vbHidden <\/b>(2)<\/li>\n<li><b>vbSystem <\/b>(4)<\/li>\n<li><b>vbArchive <\/b>(32)<\/li>\n<\/ul>\n<p>Wenn wir nur eines der Attribute setzen und alle anderen entfernen wollen (au&szlig;er <b>vbDirectory<\/b>), k&ouml;nnen wir dieses einfach zuweisen:<\/p>\n<pre>SetAttr currentproject.Path & \"\\Test.txt\", vbReadonly\r\n  GetAttr(CurrentProject.Path & \"\\Test.txt\")\r\n1<\/pre>\n<p>Eigentlich k&ouml;nnen wir nur Attribute setzen und damit alle anderen ver&auml;nderbaren Attribute aufheben. Wenn wir <b>vbReadOnly <\/b>setzen, werden <b>vbHidden<\/b>, <b>vbSystem <\/b>und <b>vbArchive <\/b>entfernt.<\/p>\n<p>Wenn wir zwei der Attribute setzen wollen, m&uuml;ssen wir diese kombinieren:<\/p>\n<pre>SetAttr currentproject.Path & \"\\Test.txt\", vbReadonly Or vbHidden\r\n  GetAttr(CurrentProject.Path & \"\\Test.txt\")\r\n  3 <\/pre>\n<p>Dabei werden die Zahlenwerte addiert, die sich hinter den Konstanten verbergen, in diesem Fall <b>1 + 2<\/b>.<\/p>\n<h2>Dateien und Verzeichnisse umbenennen<\/h2>\n<p>Eine nicht selten vorkommende Anforderung ist das Umbenennen von Dateien oder Verzeichnissen. Die Name-Anweisung entspricht nicht der &uuml;blichen Syntax f&uuml;r Methoden oder Anweisungen, sondern sie besteht aus mehreren Teilen:<\/p>\n<pre>Name [AlterName]<span style=\"color:blue;\"> As <\/span>[NeuerName]<\/pre>\n<p>Die folgende Prozedur erstellt im aktuellen Datenbankverzeichnis ein Verzeichnis namens <b>VorDemUmbenennen<\/b>. Mit der <b>Name<\/b>-Anweisung benennt es dieses Verzeichnis dann in <b>NachDemUmbenennen <\/b>um: <\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>VerzeichnisUmbenennen()\r\n     <span style=\"color:blue;\">Dim <\/span>strVorDemUmbenennen<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strNachDemUmbenennen<span style=\"color:blue;\"> As String<\/span>\r\n     strVorDemUmbenennen = CurrentProject.Path _\r\n         & \"\\VorDemUmbenennen\"\r\n     strNachDemUmbenennen = CurrentProject.Path _\r\n         & \"\\NachDemUmbenennen\"\r\n     MkDir strVorDemUmbenennen\r\n     Name strVorDemUmbenennen<span style=\"color:blue;\"> As <\/span>strNachDemUmbenennen\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Das Gleiche funktioniert auch f&uuml;r Dateien. Dazu gibt man einfach den Pfad zum aktuellen Namen der Datei an und dann den Pfad zu der Datei mit dem neuen Namen.<\/p>\n<h2>Open, Close und Co.<\/h2>\n<p>Wir haben eingangs einige Elemente der <b>FileSystem<\/b>-Klasse kennengelernt, die wir hier nicht vorgestellt haben, zum Beispiel <b>EOF<\/b>, <b>FileLen<\/b>, <b>FreeFile<\/b>, <b>Loc<\/b>, <b>LOF<\/b>,  <b>Reset<\/b> und <b>Seek<\/b>.<\/p>\n<p>Diese werden vor allem im Zusammenhang mit Funktionen zum Erstellen, &Auml;ndern und Lesen von Textdateien verwendet.<\/p>\n<p>Die dazu notwendigen Anweisungen wie <b>Open<\/b>, <b>Close<\/b>, <b>Input<\/b>, <b>Line Input<\/b>, <b>Print <\/b>oder <b>Write <\/b>werden interessanterweise im Objektkatalog nicht abgebildet.<\/p>\n<p>Das Bearbeiten von Textdateien mit diesen Anweisungen beschreiben wir unter anderem in einem weiteren Artikel namens <b>VBA und Textdateien: Alles &uuml;ber Open, Close, Print und Co. <\/b>(<b>www.vbentwickler.de\/454<\/b>).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Die Verwaltung von Dateien per Code ist &ouml;fter gefragt, als man denkt. Damit lassen sich Verzeichnisse erstellen, auslesen und entfernen, Dateien erstellen, l&ouml;schen und bearbeiten und vieles mehr. Leider sind die Bordmitteln von VBA hier teilweise ein wenig sperrig. Allerdings sind sie f&uuml;r einfache Aufgaben durchaus ausreichend und erfordern nicht den Einsatz einer zus&auml;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&ouml;nnen und zeigen, was sich damit alles anstellen l&auml;sst. Schlie&szlig;lich schauen wir aber auch noch kritisch auf m&ouml;gliche Nachteile.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[662024,66062024,44000023,44000025],"tags":[],"yst_prominent_words":[],"class_list":["post-55000453","post","type-post","status-publish","format-standard","hentry","category-662024","category-66062024","category-PowerApps","category-VBAProgrammierung"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000453","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/comments?post=55000453"}],"version-history":[{"count":0,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000453\/revisions"}],"wp:attachment":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/media?parent=55000453"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/categories?post=55000453"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/tags?post=55000453"},{"taxonomy":"yst_prominent_words","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/yst_prominent_words?post=55000453"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}