Rekursive Datei/Ordner Auflistung

  • Hi,
    ich habe vor einer Zeit mal eine UDF für mich erstellt, mit der ich alle Dateien in Unterordnern auflisten kann.
    Diese habe ich nun generalüberholt.
    Schaut sie euch mal an.
    Was kann ich noch verbessern?

    Warum ist meine UDF viel schneller als die von BugFix (teilweise bis zu 10 Mal :D )

    Spoiler anzeigen
    [autoit]

    #include-once
    #include <Array.au3>
    #include <File.au3>

    [/autoit] [autoit][/autoit] [autoit]

    ;*******************************************************************************************************************************************************************************************************************************************
    ; Funktion _ordner_rekursiv($udf_quellordner[, $udf_Ordner_Dateien[, $udf_unterordner=True[, $udf_spalte_datum=False[, $udf_dateityp = "*"[, $udf_auslassen = ""]]]]])
    ; Beschreibung ermittelt alle Dateien/Ordner des angegebenen Verzeichnisses
    ; Parameter $udf_quellordner: der zu durchsuchende Ordner (Angabe: einzelner Ordner als String oder mehrere Ordner im Array beginnend bei 1)
    ; optional $udf_Ordner_Dateien: 1 = Dateien auflisten (Standard) 2 = Ordner auflisten
    ; optional $udf_unterordner: True = Unterordner miteinbeziehen (Standard) False = Unterordner nicht miteinbeziehen
    ; optional $udf_spalte_datum: True = Änderungsdatum der Datei ermitteln False = Änderungsdatum der Datei nicht ermitteln (Standard)
    ; optional $udf_dateityp: einzuschließende Dateitypen (mehrere Typen durch | trennen) "*" >>> alle (Standard)
    ; optional $udf_auslassen: Wörter, die im Pfad oder Dateinamen vorkommen, auslassen (mehrere durch | trennen) "" <<< Standard
    ; Rückgabewert Erfolg: Gibt ein Array mit 3 Spalten zurück (Dateiname, Dateipfad, Änderungsdatum)
    ; Fehler: 0 setzt @error
    ; @error = 1 mindestens 1 Pfad existiert nicht
    ; Autor Tweaky (http://www.autoit.de)
    ;*******************************************************************************************************************************************************************************************************************************************

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;********************************************
    ; Ordner rekursiv (Hauptfunktion) *
    ;********************************************

    [/autoit] [autoit][/autoit] [autoit]

    Func _ordner_rekursiv($udf_quellordner, $udf_Ordner_Dateien = 1, $udf_unterordner = True, $udf_spalte_datum = False, $udf_dateityp = "*", $udf_auslassen = "")
    Local $verzeichnisse_alle[1] ;Array für die Ordner
    Local $array_alles[1000000][3] ;Array für die Ordner und Dateien
    Local $szDrive, $szDir, $szFName, $szExt

    [/autoit] [autoit][/autoit] [autoit]

    If Not IsArray($udf_quellordner) Then ;Falls der Quellordner kein Array ist, ein Array erstellen
    $udf_quellordner_tmp = $udf_quellordner
    Dim $udf_quellordner[2]
    $udf_quellordner[0] = 1
    $udf_quellordner[1] = $udf_quellordner_tmp
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 1 To UBound($udf_quellordner) - 1
    If Not FileExists($udf_quellordner[$i]) Or Not StringInStr($udf_quellordner[$i], ":") Then
    SetError(1) ;mindestens 1 Pfad existiert nicht
    Return 0
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    If StringRight($udf_quellordner[$i], 1) <> "\" Then $udf_quellordner[$i] &= "\"

    [/autoit] [autoit][/autoit] [autoit]

    $udf_quellordner_einzeln = $udf_quellordner[$i]

    [/autoit] [autoit][/autoit] [autoit]

    If $udf_unterordner = True Then ;mit Unterordner
    _ordner_rekursiv_mit_unterordner($udf_quellordner_einzeln, $verzeichnisse_alle)
    _ArrayAdd($verzeichnisse_alle, $udf_quellordner_einzeln)
    Else ;ohne Unterordner
    $verzeichnisse_alle = $udf_quellordner
    EndIf
    Next

    [/autoit] [autoit][/autoit] [autoit]

    If IsArray($verzeichnisse_alle) Then $verzeichnisse_alle[0] = UBound($verzeichnisse_alle) - 1 ;In die erste Zeile die Anzahl der Dateien schreiben

    [/autoit] [autoit][/autoit] [autoit]

    $zaehler_fortlaufend = 0

    [/autoit] [autoit][/autoit] [autoit]

    If $udf_Ordner_Dateien = 1 Then ;Dateien auflisten

    [/autoit] [autoit][/autoit] [autoit]

    If Not IsArray($verzeichnisse_alle) Then
    $verzeichnisse_alle_tmp = $verzeichnisse_alle
    Local $verzeichnisse_alle[2] ;Array für die Ordner
    $verzeichnisse_alle[1] = $verzeichnisse_alle_tmp
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    For $u = 1 To UBound($verzeichnisse_alle) - 1
    $array_alle_dateien = _FileListToArray($verzeichnisse_alle[$u], "*", 1)

    [/autoit] [autoit][/autoit] [autoit]

    For $k = 1 To UBound($array_alle_dateien) - 1
    $kriterien_ok = 0

    [/autoit] [autoit][/autoit] [autoit]

    If $udf_dateityp = "*" Then ;Dateityp nicht angegeben oder alle Dateien
    $kriterien_ok = 1
    Else ;1 oder mehrere Dateitypen angegeben
    $dateityp_split = StringSplit($udf_dateityp, "|")
    $udf_dateiendung_array = _PathSplit($array_alle_dateien[$k], $szDrive, $szDir, $szFName, $szExt)
    $udf_dateiendung = $udf_dateiendung_array[4]
    For $i = 1 To UBound($dateityp_split) - 1
    If "." & $dateityp_split[$i] = StringRight($array_alle_dateien[$k], StringLen($udf_dateiendung)) Then
    $kriterien_ok = 1
    ExitLoop
    EndIf
    Next
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    If $udf_auslassen <> "" Then ;Wörter in dem Pfad und Datei auslassen
    $auslassen_split = StringSplit($udf_auslassen, "|")
    For $i = 1 To UBound($auslassen_split) - 1
    If StringInStr($array_alle_dateien[$k], $auslassen_split[$i]) Or StringInStr($verzeichnisse_alle[$u], $auslassen_split[$i]) Then
    $kriterien_ok = 0
    ExitLoop
    EndIf
    Next
    EndIf

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;Papierkorb und System Volume Information wird nicht aufgelistet
    If StringInStr($array_alle_dateien[$k], 'RECYCLER') Or StringInStr($verzeichnisse_alle[$u], 'RECYCLER') _
    Or StringInStr($array_alle_dateien[$k], 'RECYCLED') Or StringInStr($verzeichnisse_alle[$u], 'RECYCLED') _
    Or StringInStr($array_alle_dateien[$k], 'System Volume Information') Or StringInStr($verzeichnisse_alle[$u], 'System Volume Information') _
    Or StringInStr($array_alle_dateien[$k], '$RECYCLE.BIN') Or StringInStr($verzeichnisse_alle[$u], '$RECYCLE.BIN') Then
    $kriterien_ok = 0
    ExitLoop
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ;wenn der Dateityp passt und die Datei bzw. der Ordner nicht ausgelassen werden soll
    If $kriterien_ok = 1 Then
    $zaehler_fortlaufend += 1
    $array_alles[$zaehler_fortlaufend][0] = $verzeichnisse_alle[$u]
    $array_alles[$zaehler_fortlaufend][1] = $array_alle_dateien[$k]
    If $udf_spalte_datum = True Then $array_alles[$zaehler_fortlaufend][2] = FileGetTime($verzeichnisse_alle[$u] & $array_alle_dateien[$k], 0, 1)
    EndIf
    Next
    Next

    [/autoit] [autoit][/autoit] [autoit]

    Else ;Ordner auflisten
    For $i = 1 To UBound($verzeichnisse_alle) - 1
    $kriterien_ok = 1

    [/autoit] [autoit][/autoit] [autoit]

    ;Papierkorb und System Volume Information wird nicht aufgelistet
    If StringInStr($verzeichnisse_alle[$i], 'RECYCLER') Or StringInStr($verzeichnisse_alle[$i], 'RECYCLED') _
    Or StringInStr($verzeichnisse_alle[$i], 'System Volume Information') Or StringInStr($verzeichnisse_alle[$i], '$RECYCLE.BIN') Then
    $kriterien_ok = 0
    ExitLoop
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    If $kriterien_ok = 1 Then
    $zaehler_fortlaufend += 1
    $array_alles[$zaehler_fortlaufend][0] = $verzeichnisse_alle[$i]
    EndIf
    Next
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ;Leere Zeilen am Ende löschen
    ReDim $array_alles[$zaehler_fortlaufend + 1][3]

    [/autoit] [autoit][/autoit] [autoit]

    ;In die erste Zeile die Anzahl der Dateien schreiben
    If IsArray($array_alles) Then $array_alles[0][0] = UBound($array_alles) - 1

    [/autoit] [autoit][/autoit] [autoit]

    $verzeichnisse_alle = 0 ;Array löschen

    [/autoit] [autoit][/autoit] [autoit]

    Return $array_alles ;Array zurückgeben
    EndFunc ;==>_ordner_rekursiv

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;**************************************
    ; Unterordner durchsuchen *
    ;**************************************

    [/autoit] [autoit][/autoit] [autoit]

    Func _ordner_rekursiv_mit_unterordner($udf_quellordner, ByRef $verzeichnisse_alle)
    $verzeichnisse = _FileListToArray($udf_quellordner, "*", 2)

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 1 To UBound($verzeichnisse) - 1
    $verzeichnisse[$i] = $udf_quellordner & $verzeichnisse[$i] & "\"
    _ArrayAdd($verzeichnisse_alle, $verzeichnisse[$i])
    _ordner_rekursiv_mit_unterordner($verzeichnisse[$i], $verzeichnisse_alle)
    Next
    EndFunc ;==>_ordner_rekursiv_mit_unterordner

    [/autoit]

    PS: Hoffe es gefällt mein Skriptstil.
    Ist denke ich nicht der beste, aber ich blick durch :P
    Fehlerhändling ist nicht so mein Ding :whistling:

  • Wow, nicht schlecht ^^
    ist wirklich ein stückchen schneller (1 sekunde bei 7000 dateien)
    ABER:
    Warum habe ich bei dem Scan mit deiner UDF
    7098 dateien und bei dem Scan mit der UDF von Bugfix
    7281 dateien ?
    wo sind die verbliebenen?^^ (hab nur standard werte benutzt und als dir den desktop angegeben - bei beiden udfs)

    Wer immer nur das tut, was er bereits kann - wird auch immer nur das bleiben, was er bereits ist!

  • Was meinst du mit Desktop als Pfad?
    Was hast du da genau eingegeben?

    Nur 1 Sekunde bei 7000 Dateien - hm ist bei mir deutlich mehr 8|

    Der Ordner Papierkorb und System Volume Information wird nicht erfasst

    Bsp: Ordner "C:\windows"
    eigen 4.32 Sekunden 14443 Dateien
    BugFix 19.34 Sekunden 14443 Dateien

  • das ist mein code:

    Spoiler anzeigen
    [autoit]


    $zeit1 = 0
    $zeit2 = 0
    For $i = 1 To 5
    Sleep(1000)
    $t = TimerInit()
    $2 = _ordner_rekursiv(@DesktopDir)
    $s = TimerDiff($t)
    $zeit1 = $zeit1 + $s / 1000
    Next
    MsgBox(0, "Zeit", $zeit1 / 5) ;3,8597

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    For $i = 1 To 5
    Sleep(1000)
    $t = TimerInit()
    $1 = _GetFilesFolder_Rekursiv(@DesktopDir)
    $s = TimerDiff($t)
    $zeit2 = $zeit2 + $s / 1000
    Next
    MsgBox(0, "Zeit", $zeit2/5); 5,4076

    [/autoit] [autoit][/autoit] [autoit]

    _ArrayDisplay($2); 7089
    _ArrayDisplay($1); 7281

    [/autoit]

    Wer immer nur das tut, was er bereits kann - wird auch immer nur das bleiben, was er bereits ist!

  • bei mir werden so nur 10 Dateien angezeigt.
    Deshalb kann ich es nicht testen.

    Mal schauen was die anderen meinen.

    PS: gib doch mal @WindowsDir an.

  • :wacko: das folgende hätte ich nicht erwartet:
    deine UDF findet im windir 59158 Dateien
    Bugfix's Udf hat sogar 70906 Dateien
    gut das ist ja noch nicht soo verwunderlich .. aber DAS:
    Der Scan mit deiner UDF (1 durchgang) 145,27 sekunden
    und der Scan mit Bugfix's UDF 41,46 sekunden
    Es ist aber noch zu sagen, dass zwischen den beiden durchläufen
    KEIN sleep war und ich mit deiner UDF angefangen habe.
    (Spielt das irgendeine Rolle?)
    PS: Ich habe bei beiden nur einen Durchlauf gemacht

    Wer immer nur das tut, was er bereits kann - wird auch immer nur das bleiben, was er bereits ist!

    • Offizieller Beitrag

    Das spielt eine große Rolle, denn wenn man bereits einmal alle Dateien durchgescannt hat, dann befinden sich diese beim zweiten Scan im Festplatten-Cache und der zweite Scan geht dann wesentlich schneller.
    Also entweder mehrere Durchläufe machen und das Ergebnis mitteln oder gleiche Anfangsbedingungen schaffen (z.B. jeweils nach einem Neustart).

    Edit:
    Tweaky: Ich kann Dein Ergebnis nicht bestätigen. BugFix's Version ist bei meinen Tests (jeweils mehrere Scans hintereinander) etwas schneller als Deine Version. Noch schneller ist allerdings meine Version ;)

    Spoiler anzeigen
    [autoit]


    ;===============================================================================
    ; Function Name: _RecursiveFileListToArray($sPath, $sPattern, $iFlag = 0, $iFormat = 1, $sDelim = @CRLF)
    ; Description:: gibt Verzeichnisse und/oder Dateien (rekursiv) zurück, die
    ; einem RegExp-Pattern entsprechen
    ; Parameter(s): $sPath = Startverzeichnis
    ; $sPattern = ein beliebiges RexExp-Pattern für die Auswahl
    ; $iFlag = Auswahl
    ; 0 = Dateien & Verzeichnisse
    ; 1 = nur Dateien
    ; 2 = nur Verzeichnisse
    ; $iFormat = Rückgabeformat
    ; 0 = String
    ; 1 = Array mit [0] = Anzahl
    ; 2 = Nullbasiertes Array
    ; $sDelim = Trennzeichen für die String-Rückgabe
    ; Requirement(s): AutoIt 3.3.0.0
    ; Return Value(s): Array/String mit den gefundenen Dateien/Verzeichnissen
    ; Author(s): Oscar (http://www.autoit.de)
    ; Anregungen von: bernd670 (http://www.autoit.de)
    ;===============================================================================
    Func _RecursiveFileListToArray($sPath, $sPattern, $iFlag = 0, $iFormat = 1, $sDelim = @CRLF)
    Local $hSearch, $sFile, $sReturn = ''
    If StringRight($sPath, 1) <> '\' Then $sPath &= '\'
    $hSearch = FileFindFirstFile($sPath & '*.*')
    If @error Or $hSearch = -1 Then Return SetError(0, 0, $sReturn)
    While True
    $sFile = FileFindNextFile($hSearch)
    If @error Then ExitLoop
    If StringInStr(FileGetAttrib($sPath & $sFile), 'D') Then
    If StringRegExp($sPath & $sFile, $sPattern) And ($iFlag = 0 Or $iFlag = 2) Then $sReturn &= $sPath & $sFile & '\' & $sDelim
    $sReturn &= _RecursiveFileListToArray($sPath & $sFile & '\', $sPattern, $iFlag, 0)
    ContinueLoop
    EndIf
    If StringRegExp($sFile, $sPattern) And ($iFlag = 0 Or $iFlag = 1) Then $sReturn &= $sPath & $sFile & $sDelim
    WEnd
    FileClose($hSearch)
    If $iFormat Then Return StringSplit(StringTrimRight($sReturn, StringLen($sDelim)), $sDelim, $iFormat)
    Return $sReturn
    EndFunc

    [/autoit]

    Jeweils so aufgerufen (Funktionsaufruf natürlich entsprechend):

    [autoit]


    $iTimer = TimerInit()
    $a = _RecursiveFileListToArray(@WindowsDir, '', 1)
    ConsoleWrite(TimerDiff($iTimer) & @CRLF)
    _ArrayDisplay($a)

    [/autoit]
  • so jetzt aber,
    ich habe jetzt jedes einzeln nach einem Neustart getestet:

    Zitat

    Oscar 4.24 Sekunden 14429
    eigen 8.58 Sekunden 14429
    BugFix 22.23 Sekunden 14429

    Meines soll immernoch deutlich schneller sein als das von BugFix.

    So hab ich es aufgerufen

    Spoiler anzeigen
    [autoit]

    $pfad = @WindowsDir

    [/autoit] [autoit][/autoit] [autoit]

    $begin3 = TimerInit()
    $dateien3 = _RecursiveFileListToArray($pfad, '', 1)
    $dif3 = TimerDiff($begin3)
    ConsoleWrite("Oscar" & @TAB & Round($dif3 / 1000, 2) & " Sekunden" & @TAB & UBound($dateien3) - 1 & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    $begin1 = TimerInit()
    $dateien1 = _ordner_rekursiv($pfad, 1)
    $dif1 = TimerDiff($begin1)
    ConsoleWrite("eigen" & @TAB & Round($dif1 / 1000, 2) & " Sekunden" & @TAB & UBound($dateien1) - 1 & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    $begin2 = TimerInit()
    $dateien2 = _GetFilesFolder_Rekursiv($pfad, '*', 0)
    $dif2 = TimerDiff($begin2)
    ConsoleWrite("BugFix" & @TAB & Round($dif2 / 1000, 2) & " Sekunden" & @TAB & UBound($dateien2) - 1 & @CRLF)

    [/autoit]

    Kann es vielleicht am PC liegen, dass meines und euer Ergebnis so unterschiedlich ist?
    Ich habe einen Quad Q9550 :D

    • Offizieller Beitrag

    Die absoluten Unterschiede könnten am Prozessor (und der Festplatte) liegen, aber relativ (alle Tests auf demselben Rechner) müssten die Unterschiede vergleichbar sein.

    Ich habe die Tests nicht jeweils nach einem Neustart gemacht, dass heißt bei meinen Tests spielte die Geschwindigkeit des mehrmaligen Aufrufs eine Rolle.
    Wenn BugFix's Version bei Dir so schlecht abschneidet, hat das vermutlich mit dem "Scripting.FileSystemObject" zu tun. :S
    Vielleicht muss das Object erst einmal aufgerufen worden sein (weil da von Windows noch irgendwas geladen wird)?

  • So wie es aussieht hängt es stark mit der CPU zusammen.

    gemessen jeweils nach einem Neustart