FSO gegen Dir(): Und der Gewinner ist …
Vor einer Weile habe ich für einen Kunden eine Funktion geschrieben, mit der PDF-Dateien, die bestimmte Nummern im Dateinamen enthalten, in einem nicht indizierten Netzwerkordner ermittelt und an eine Mail anhängt werden. Mit dem FileSystem-Objekt wurden die Dateien im Verzeichnis durchlaufen und der Dateiname auf das Vorkommen der Nummern geprüft. Bei Übereinstimmung wurden sie an die Mail angehängt.
Mit der Zeit gab es immer mehr Dateien im Ordner und die Funktion wurde entsprechend langsamer. Also musste ich mir die Funktion noch einmal angesehen. Die Prüfung auf die Nummern erfolgte (zugegebenermaßen nicht sehr elegant) mit zwei langsamen InStr(). Ich habe sie auf ein wenig Arithmetik und die Left()-Funktion umgestellt. Das hat die Wartezeit immerhin fast halbiert.
Da der weitere Zuwachs an Dateien aber vorhersehbar war und die Suchzeit relativ zur Anzahl ansteigt, musste eine andere Lösung her. Mit einer Suche mit Platzhalterzeichen (Wildcards) könnten die Dateien schnell gefunden werden, aber das FSO kann das leider nicht.
Die allgemein nicht mehr sehr geschätzte Dir()-Funktion kann aber mit Platzhaltern arbeiten. Also habe ich versuchsweise die Suchschleife auf Dir() umgestellt und konnte die Suchzeit drastisch verringern. Erst nach dem Vergrößern des Ordners auf über 5.000 Dokumente konnte ich die Differenz in Sekunden messen: Statt der 46 Sekunden des FSO brauchte die Dir()-Funktion mit Platzhaltersuche nur noch eine Sekunde.
Mein sehr geschätzter Access-Stammtischbruder Martin Asal schreibt im VBA-Tutorial bei "Dateien und Verzeichnisse" z. B.: "Diese Befehle sind eigentlich veraltet. Für einen moderneren, objektbasierten Zugriff gibt es das FileSystemObject.". Dem kann ich jetzt guten Gewissens hinzufügen: Aber unterschätzt mir nicht die guten alten, einfachen Funktionen, denn diese sind manchmal deutlich schneller. Vielleicht sogar, weil Sie nicht so modern und objektorientiert sind?
Und nun zur Anfangsfrage: Was ist nun besser, FSO oder Dir()? Dazu gibt es eine ganz klare Antwort: Es kommt immer darauf an!
Code
Hier der (stark vereinfachte) Code mit etwas vereinfachten Dokumentennamen und ohne Variablen. Der Iif dient im eigentlichen Programm dazu, evtl. angehängte Versionsnummern zu erkennen (die Variable ist im Beispiel – wie anderen Variablen auch – durch eine fixe Zahl ersetzt), da immer nur die neueste Version ermittelt werden soll.
Public Function DirTest()
Dim objFSO As Object
Dim objFolder As Object
Dim objFile As Object
Dim FolderName As String
Dim FileName As String
Dim i As Integer
Dim j As Integer
Dim d As Date
' FSO 1
d = Now()
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder("G:\Test\Dokumente\")
For Each objFile In objFolder.Files
j = j + 1
If InStr(objFile.Name, "12345" & IIf(1 = 0, "", "_1")) > 0 _
And InStr(objFile.Name, "123") > 0 Then
i = i + 1
End If
Next objFile
Debug.Print "FSO: " & i & " von " & j & " Dateien in " & Format(Now() - d, "nn:ss")
' Reset
i = 0
j = 0
' FSO 2
d = Now()
For Each objFile In objFolder.Files
j = j + 1
If Left(objFile.Name, Len("123-12345" & IIf(1 = 0, "", "_1"))) _
= "123-12345" & IIf(1 = 0, "", "_1") Then
i = i + 1
End If
Next objFile
Debug.Print "FSO: " & i & " von " & j & " Dateien in " & Format(Now() - d, "nn:ss")
' Reset
i = 0
j = 0
' Dir
d = Now()
FolderName = "G:\Test\Dokumente\"
FileName = Dir(FolderName & "103-64885" & IIf(1 = 0, "", "_1") & "*.pdf")
Do While FileName <> ""
i = i + 1
j = j + 1
Debug.Print FileName
FileName = Dir()
Loop
Debug.Print "Dir(): " & i & " von " & j & " Dateien in " & Format(Now() - d, "nn:ss")
End Function
Und das ist das Ergebnis:
FSO 1: 4 von 5412 Dateien in 00:46
FSO 2: 4 von 5412 Dateien in 00:28
Dir(): 4 von 4 Dateien in 00:01