FileListToArray im gesamten Verzeichnisbaum aber nicht rekursiv

  • Guten Morgen!

    AspirinJunkie
    Bei deinen Funktionen ist ein grundsätzlicher Abfrage Fehler bei der REPARSE_POINT abfrage.

    [autoit]

    If @error And BitAND($aD[0],0x400) Then ContinueLoop

    [/autoit]


    End weder, was ich nicht empfehle würde

    [autoit]

    If @error Or BitAND($aD[0],0x400) Then ContinueLoop

    [/autoit]


    Eher

    [autoit]

    If @error Then Return ;.....
    If BitAND($aD[0],0x400) Then ContinueLoop

    [/autoit]


    Lg Kleiner

  • Kleiner
    Jepp das wars - danke dir.
    Manchmal wäre Copy & Paste doch mal angebracht - die rekursive Variante war nämlich richtig.

    Oscar
    Und das beantwortet uns auch gleich die Frage warum die rekursive Funktion weniger gefunden hat als die iterative:
    Die iterative (und auch deine) hat zu viel gefunden!
    "C:\Users\All Users\" ist ein Reparse Point.
    Daher sind die darin enthaltenen Dateien doppelt im Array.

    Nun also die 3 Varianten der Funktion entsprechend berichtigt nochmal zusammengefasst:

    Funktionen für Datei Auflistungen
    [autoit]

    ; #FUNCTION# ======================================================================================
    ; Name ..........: FLwDict()
    ; Description ...: Findet Dateien und/oder Ordner in einem Verzeichnisbaum
    ; Syntax ........: FLwStr($sSD, Const[ $sPat = '', Const[ $iF = 3]])
    ; Parameters ....: $sSD - Suchort (mehrere Suchorte durch | trennen)
    ; Const $sPat - [optional] regulärer Ausdruck für zu findende Datei/Ordnernamen (default:'')
    ; Const $iF - [optional] 1=nur Dateien, 2=nur Ordner, 3=Dateien+Ordner (default:3)
    ; Const $iSSFlag - [optional] 0=Rückgabearray mit Anzahl Elemente in $Array0, 2=Rückgabearray ohne Anzahl Elemente
    ; Return values .: Success - Return Array with Matches with $Array[0] = Count
    ; Failure - Return "" and set @error
    ; Author ........: AspirinJunkie
    ; Remarks .......: Funktionsweise ist iterativ - nicht rekursiv
    ; Example .......: Yes
    ; #include <Array.au3>
    ; $aTmp = FLwStr(@WindowsDir & '|' & @ProgramFilesDir, "^Temp$", 2)
    ; _ArrayDisplay($aTmp)
    ; =================================================================================================
    Func FLwDict($sSD, Const $sPat = '', Const $iF = 3, Const $iSSFlag = 0)
    ;by AspirinJunkie
    Local $sRet = "", $oSubD = ObjCreate('Scripting.Dictionary')
    For $i In StringSplit($sSD, '|', 2)
    If StringRight($i, 1) = '\' Then $i = StringTrimRight($i, 1)
    If Not FileExists($i) Then Return SetError(2, 0, "")
    $oSubD.add($i, 0)
    Next
    Local $FFFF, $FFNF
    Local $aD, $hDLL = DllOpen('kernel32.dll')
    If Not ($iF = 3 Or $iF = 1 Or $iF = 2) Then Return SetError(3, 0, "")
    Do
    For $sDir In $oSubD.Keys
    $oSubD.Remove($sDir)
    $FFFF = FileFindFirstFile($sDir & '\*')
    If $FFFF <> -1 Then
    Do
    $FFNF = FileFindNextFile($FFFF)
    If @error Then ExitLoop
    If @extended Then
    If BitAND(StringRegExp($FFNF, $sPat) * 2, $iF) Then $sRet &= $sDir & '\' & $FFNF & '\|'
    $aD = DllCall($hDLL, 'dword', 'GetFileAttributesW', 'wstr', $sDir & '\' & $FFNF)
    If @error Or BitAND($aD[0], 0x400) Then ContinueLoop
    $oSubD.add($sDir & '\' & $FFNF, 0)
    ElseIf BitAND(StringRegExp($FFNF, $sPat), $iF) Then
    $sRet &= $sDir & '\' & $FFNF & '|'
    EndIf
    Until 0
    FileClose($FFFF)
    EndIf
    Next
    Until $oSubD.Count = 0
    DllClose($hDLL)
    Return StringSplit(StringTrimRight($sRet, 1), '|', $iSSFlag)
    EndFunc ;==>FLwDict

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

    ; #FUNCTION# ======================================================================================
    ; Name ..........: FLwStr()
    ; Description ...: Findet Dateien und/oder Ordner in einem Verzeichnisbaum
    ; Syntax ........: FLwStr($sSD, Const[ $sPat = '', Const[ $iF = 3]])
    ; Parameters ....: $sSD - Suchort (mehrere Suchorte durch | trennen)
    ; Const $sPat - [optional] regulärer Ausdruck für zu findende Datei/Ordnernamen (default:'')
    ; Const $iF - [optional] 1=nur Dateien, 2=nur Ordner, 3=Dateien+Ordner (default:3)
    ; Const $iSSFlag - [optional] 0=Rückgabearray mit Anzahl Elemente in $Array0, 2=Rückgabearray ohne Anzahl Elemente
    ; Return values .: Success - Return Array with Matches with $Array[0] = Count
    ; Failure - Return "" and set @error
    ; Author ........: AspirinJunkie
    ; Remarks .......: Funktionsweise ist iterativ - nicht rekursiv
    ; Example .......: Yes
    ; #include <Array.au3>
    ; $aTmp = FLwStr(@WindowsDir & '|' & @ProgramFilesDir, "^Temp$", 2)
    ; _ArrayDisplay($aTmp)
    ; =================================================================================================
    Func FLwStr($sSD, Const $sPat = '', Const $iF = 3, Const $iSSFlag = 0)
    ;by AspirinJunkie
    Local $sRet = "", $sSubD = ""
    For $i In StringSplit($sSD, '|', 2)
    If StringRight($i, 1) = '\' Then $i = StringTrimRight($i, 1)
    If Not FileExists($i) Then Return SetError(2, 0, "")
    $sSubD &= '|' & $i
    Next
    Local $FFFF, $FFNF, $sDir, $iC
    Local $aD, $hDLL = DllOpen('kernel32.dll')
    If Not ($iF = 3 Or $iF = 1 Or $iF = 2) Then Return SetError(3, 0, "")
    Do
    $iC = StringInStr($sSubD, '|', 2, -1)
    If @error Or $iC = 0 Then ExitLoop
    $iC = StringLen($sSubD) - $iC
    $sDir = StringRight($sSubD, $iC)
    $sSubD = StringTrimRight($sSubD, $iC + 1)
    $FFFF = FileFindFirstFile($sDir & '\*')
    If $FFFF <> -1 Then
    Do
    $FFNF = FileFindNextFile($FFFF)
    If @error Then ExitLoop
    If @extended Then
    If BitAND(StringRegExp($FFNF, $sPat) * 2, $iF) Then $sRet &= $sDir & '\' & $FFNF & '\|'
    $aD = DllCall($hDLL, 'dword', 'GetFileAttributesW', 'wstr', $sDir & '\' & $FFNF)
    If @error Or BitAND($aD[0], 0x400) Then ContinueLoop
    $sSubD &= '|' & $sDir & '\' & $FFNF
    ElseIf BitAND(StringRegExp($FFNF, $sPat), $iF) Then
    $sRet &= $sDir & '\' & $FFNF & '|'
    EndIf
    Until 0
    FileClose($FFFF)
    EndIf
    Until 0
    DllClose($hDLL)
    Return StringSplit(StringTrimRight($sRet, 1), '|', $iSSFlag)
    EndFunc ;==>FLwStr

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

    ; #FUNCTION# ====================================================================================================================
    ; Name...........: FLwStrRek
    ; Description ...: Gibt ein Array mit Dateien bzw. Unterordnern im gesamten Verzeichnisbaum zurück
    ; Syntax.........: FLwStrRek($sSD, [$sPat = '*', [$iF = 0]])
    ; Parameters ....: $sSD - Startverzeichnis (mehrere Verzeichnisse durch | trennen)
    ; $sPat - Optional: Pattern zur Filterung mit regulären Ausdrücken
    ; $iF - Optional: Flag ob nur Dateien, Ordner oder beides gesucht werden sollen
    ; |$iF=3(Default) Gibt beides zurück
    ; |$iF=1 Gibt nur Dateien zurück
    ; |$iF=2 Gibt nur Ordner zurück
    ; $flgSS - Art der Rückgabe (Siehe StringSplit()-Funktion)
    ; $bS - interner Rekursionsparameter - nicht verändern!
    ; Return values .: @Error: 1 = Startverzeichnis existiert nicht.
    ; |2 = ungültiger Wert für $iF
    ; Author ........: AspirinJunkie
    ; Modified.......: 12.04.2010
    ; Remarks .......:
    ; Related .......:
    ; Link ..........:
    ; Example .......: No
    ; Note ..........: basiert auf einem rekursiven Ansatz
    ; ===============================================================================================================================
    Func FlwStrRek($sSD, Const $sPat = '', Const $iF = 3, Const $flgSS = 2, Const $bS = True)
    ; By AspirinJunkie
    Local $FFFF, $FFNF, $aD
    Local Static $sRet, $hDLL
    If $bS Then
    $hDLL = DllOpen("kernel32.dll")
    If Not ($iF = 3 Or $iF = 1 Or $iF = 2) Then Return SetError(1, DllClose($hDLL), "")
    EndIf
    For $i In StringSplit($sSD, "|", 2)
    If StringRight($i, 1) = '\' Then $i = StringTrimRight($i, 1)
    If Not FileExists($i) Then ContinueLoop
    $FFFF = FileFindFirstFile($i & '\*')
    If $FFFF <> -1 Then
    Do
    $FFNF = FileFindNextFile($FFFF)
    If @error Then ExitLoop
    If @extended Then
    If BitAND(StringRegExp($FFNF, $sPat) * 2, $iF) Then $sRet &= $i & '\' & $FFNF & "|"
    $aD = DllCall($hDLL, "dword", "GetFileAttributesW", "wstr", $i & '\' & $FFNF)
    If @error Or BitAND($aD[0], 0x400) Then ContinueLoop
    FlwStrRek($i & '\' & $FFNF, $sPat, $iF, 2, False)
    ElseIf BitAND(StringRegExp($FFNF, $sPat), $iF) Then
    $sRet &= $i & '\' & $FFNF & "|"
    EndIf
    Until 0
    FileClose($FFFF)
    EndIf
    Next
    If $bS Then
    DllClose($hDLL)
    Local $aRet = StringSplit(StringTrimRight($sRet, 1), "|", $flgSS)
    $sRet = ""
    Return $aRet
    EndIf
    EndFunc ;==>FlwStrRek

    [/autoit]

    4 Mal editiert, zuletzt von AspirinJunkie (9. September 2014 um 13:04) aus folgendem Grund: Bug in FlwStrRek behoben

  • Ich hab gesehen, dass du erst im Mai noch eine Änderung an der FlwStrRek gemacht hast, daher poste ich mal hier, obwohl es ein recht alter Post ist.

    Mit einem UNC-Pfad bekomme ich bei FlwStrRek nicht das richtige Ergebnis:


    FLwStr: 68115.0414806452 - 112727 Ergebnisse im Array
    FLwDict: 64252.1219274388 - 112727 Ergebnisse im Array
    FlwStrRek: 41.2127743281846 - 39 Ergebnisse im Array

  • Danke nuely.
    Der Grund hierfür ist das Phänomen hier im Forum, dass \" als Escape für das Anführungszeichen betrachtet wird.
    Das führte dazu, dass die Backslashs in den Pfaden fehlten.
    Hab es jetzt in einfache Anführungszeichen gesetzt.

  • Jetzt passt es:


    FLwStr: 65215.8372248165 - 112738 Ergebnisse im Array
    FLwDict: 64167.1911188656 - 112738 Ergebnisse im Array
    FlwStrRek: 65602.6551034023 - 112738 Ergebnisse im Array

  • Bei der Gelegenheit habe ich gleich mal die Variante für den neuen Datentyp Map aus den aktuellen Betas umgesetzt:

    Schnelle Datei/Ordner-Auflistung mit Filterfunktion für den Datentyp Map
    [autoit]

    $m_Ret = FLwMap(@TempDir)
    For $i In MapKeys($m_Ret)
    ConsoleWrite($m_Ret[$i] & @CRLF)
    Next

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

    ; #FUNCTION# ======================================================================================
    ; Name ..........: FLwMap()
    ; Description ...: Listet Dateien und/oder Ordner in einem Verzeichnisbaum
    ; Syntax ........: FLwStr($sSD, Const[ $sPat = '', Const[ $iF = 3]])
    ; Parameters ....: $sSD - Suchort (mehrere Suchorte durch | trennen)
    ; Const $sPat - [optional] regulärer Ausdruck für zu findende Datei/Ordnernamen (default:'')
    ; Const $iF - [optional] 1=nur Dateien, 2=nur Ordner, 3=Dateien+Ordner (default:3)
    ; Return values .: Success - Return Map with continous numbers as keys and Paths as values
    ; Failure - Return "" and set @error
    ; Author ........: AspirinJunkie
    ; Remarks .......: Funktionsweise ist iterativ - nicht rekursiv
    ; Example .......: Yes
    ; $m_Ret = FLwMap(@TempDir)
    ; For $i in MapKeys($m_Ret)
    ; ConsoleWrite($m_Ret[$i] & @CRLF)
    ; Next
    ; =================================================================================================
    Func FLwMap($sSD, Const $sPat = '', Const $iF = 3)
    ;by AspirinJunkie
    Local $mSubD[], $x, $y = -1, $mRet[]
    For $i In StringSplit($sSD, '|', 2)
    If StringRight($i, 1) = '\' Then $i = StringTrimRight($i, 1)
    If Not FileExists($i) Then Return SetError(2, 0, "")
    $x = MapAppend($mSubD, $i)
    Next
    Local $FFFF, $FFNF, $sDir
    Local $aD, $hDLL = DllOpen('kernel32.dll')
    If Not ($iF = 3 Or $iF = 1 Or $iF = 2) Then Return SetError(3, 0, "")
    Do
    $y += 1
    If $y > $x Then ExitLoop
    $sDir = $mSubD[$y]
    $FFFF = FileFindFirstFile($sDir & '\*')
    If $FFFF <> -1 Then
    Do
    $FFNF = FileFindNextFile($FFFF)
    If @error Then ExitLoop
    If @extended Then
    If BitAND(StringRegExp($FFNF, $sPat) * 2, $iF) Then MapAppend($mRet, $sDir & '\' & $FFNF)
    If @error Or BitAND(DllCall($hDLL, 'dword', 'GetFileAttributesW', 'wstr', $sDir & '\' & $FFNF)[0], 0x400) Then ContinueLoop
    $x = MapAppend($mSubD, $sDir & '\' & $FFNF)
    ElseIf BitAND(StringRegExp($FFNF, $sPat), $iF) Then
    MapAppend($mRet, $sDir & '\' & $FFNF)
    EndIf
    Until 0
    FileClose($FFFF)
    EndIf
    Until 0
    DllClose($hDLL)
    Return $mRet
    EndFunc ;==>FLwMap

    [/autoit]


    Wer die Betas derzeit testet kann damit noch ein bisschen was an Speed rausholen.