Jump to content

Modifying Melba's "recursive" file/folder search


Recommended Posts

I've been using this for quite a while (thanks Melba), and I wanted to modify it to call a function every time a file/folder is found. This way I wouldn't have to wait a long time before the main actions of my script (such as writing the path to a text file) could be executed.

Here is my work so far, but I'm not sure what else to do. I know there are a lot more spots where a call should be placed, I just don't really know where/what parameters to give the Call function.

_RecFileListToArray(@HomeDrive & "\", "_Call")

Func _Call($sPath)
    ConsoleWrite($sPath & @CRLF)
EndFunc

Func _RecFileListToArray($sInitialPath, $sFunction, $sInclude_List = "*", $iReturn = 0, $fRecur = 0, $fSort = 0, $sReturnPath = 1, $sExclude_List = "")

    Local $asReturnList[100] = [0], $asFileMatchList[100] = [0], $asRootFileMatchList[100] = [0], $asFolderMatchList[100] = [0], $asFolderList[100] = [1]
    Local $sFolderSlash = "", $sInclude_List_Mask, $sExclude_List_Mask, $hSearch, $fFolder, $sRetPath = "", $sCurrentPath, $sName

    ; Check valid path
    If Not FileExists($sInitialPath) Then Return SetError(1, 1, "")
    ; Check if folders should have trailing \ and ensure that $sInitialPath does have one
    If StringRight($sInitialPath, 1) = "\" Then
    $sFolderSlash = "\"
    Else
    $sInitialPath = $sInitialPath & "\"
    EndIf
    ; Add path to folder list
    $asFolderList[1] = $sInitialPath

    ; Determine Filter mask for SRE check
    If $sInclude_List = "*" Then
    $sInclude_List_Mask = ".+" ; Set mask to exclude base folder with NULL name
    Else
    If StringRegExp($sInclude_List, "\\|/|:|\<|\>|\|") Then Return SetError(1, 2, "") ; Check For invalid characters within $sInclude_List
    $sInclude_List = StringReplace(StringStripWS(StringRegExpReplace($sInclude_List, "\s*;\s*", ";"), 3), ";", "|") ; Strip WS and insert | for ;
    $sInclude_List_Mask = "(?i)^" & StringReplace(StringReplace(StringReplace($sInclude_List, ".", "\."), "*", ".*"), "?", ".") & "\z" ; Convert SRE pattern
    EndIf

    ; Determine Exclude mask for SRE check
    If $sExclude_List = "" Then
    $sExclude_List_Mask = ":" ; Set unmatchable mask
    Else
    If StringRegExp($sExclude_List, "\\|/|:|\<|\>|\|") Then Return SetError(1, 7, "") ; Check For invalid characters within $sInclude_List
    $sExclude_List = StringReplace(StringStripWS(StringRegExpReplace($sExclude_List, "\s*;\s*", ";"), 3), ";", "|") ; Strip WS and insert | for ;
    $sExclude_List_Mask = "(?i)^" & StringReplace(StringReplace(StringReplace($sExclude_List, ".", "\."), "*", ".*"), "?", ".") & "\z" ; Convert $sExclude_List to SRE pattern
    EndIf

    ; Verify other parameter values
    If Not ($iReturn = 0 Or $iReturn = 1 Or $iReturn = 2) Then Return SetError(1, 3, "")
    If Not ($fRecur = 0 Or $fRecur = 1) Then Return SetError(1, 4, "")
    If Not ($fSort = 0 Or $fSort = 1) Then Return SetError(1, 5, "")
    If Not ($sReturnPath = 0 Or $sReturnPath = 1 Or $sReturnPath = 2) Then Return SetError(1, 6, "")

    ; Search in listed folders
    While $asFolderList[0] > 0

    ; Set path to search
    $sCurrentPath = $asFolderList[$asFolderList[0]]
    ; Reduce folder array count
    $asFolderList[0] -= 1

    ; Determine return path to add to file/folder name
    Switch $sReturnPath
    ; Case 0 ; Name only
    ; Leave as ""
    Case 1 ; Initial path not included
    $sRetPath = StringReplace($sCurrentPath, $sInitialPath, "")
    Case 2 ; Initial path included
    $sRetPath = $sCurrentPath
    EndSwitch

    If $fSort Then

    ; Get folder name
    $sName = StringRegExpReplace(StringReplace($sCurrentPath, $sInitialPath, ""), "(.+?\\)*(.+?)(\\.*?(?!\\))", "$2")

    ; Get search handle
    $hSearch = FileFindFirstFile($sCurrentPath & "*")
    ; If folder empty move to next in list
    If $hSearch = -1 Then ContinueLoop

    ; Search folder
    While 1
    $sName = FileFindNextFile($hSearch)
    ; Check for end of folder
    If @error Then ExitLoop
    ; Check for file - @extended set for subfolder in 3.3.1.1 +
    If @extended Then
    ; If recursive search, add subfolder to folder list
    If $fRecur Then _RFLTA_AddToList($asFolderList, $sCurrentPath & $sName & "\")

    ; Add folder name if matched against Include/Exclude masks
    If StringRegExp($sName, $sInclude_List_Mask) And Not StringRegExp($sName, $sExclude_List_Mask) Then _
    _RFLTA_AddToList($asFolderMatchList, $sRetPath & $sName & $sFolderSlash)

    Else
    ; Add file name if matched against Include/Exclude masks
    If StringRegExp($sName, $sInclude_List_Mask) And Not StringRegExp($sName, $sExclude_List_Mask) Then
    If $sCurrentPath = $sInitialPath Then
    _RFLTA_AddToList($asRootFileMatchList, $sRetPath & $sName)
    Else
    _RFLTA_AddToList($asFileMatchList, $sRetPath & $sName)
    EndIf
    EndIf
    EndIf
    WEnd

    ; Close current search
    FileClose($hSearch)

    Else ; No sorting required

    ; Get search handle
    $hSearch = FileFindFirstFile($sCurrentPath & "*")
    ; If folder empty move to next in list
    If $hSearch = -1 Then ContinueLoop

    ; Search folder
    While 1
    $sName = FileFindNextFile($hSearch)
    ; Check for end of folder
    If @error Then ExitLoop
    ; Check for subfolder - @extended set in 3.3.1.1 +
    $fFolder = @extended

    ; If recursive search, add subfolder to folder list
    If $fRecur And $fFolder Then _RFLTA_AddToList($asFolderList, $sCurrentPath & $sName & "\")

    ; Check file/folder type against required return value and file/folder name against Include/Exclude masks
    If $fFolder + $iReturn <> 2 And StringRegExp($sName, $sInclude_List_Mask) And Not StringRegExp($sName, $sExclude_List_Mask) Then
    ; Add final "\" to folders
    If $fFolder Then $sName &= $sFolderSlash
    _RFLTA_AddToList($asReturnList, $sRetPath & $sName)
                    Call($sFunction, $sRetPath & $sName) ;CALL HERE------------------------------------------------------------------------------------
    EndIf
    WEnd

    ; Close current search
    FileClose($hSearch)

    EndIf

    WEnd

    If $fSort Then

    ; Check if any file/folders have been added
    If $asRootFileMatchList[0] = 0 And $asFileMatchList[0] = 0 And $asFolderMatchList[0] = 0 Then Return SetError(1, 8, "")

    Switch $iReturn
    Case 2 ; Folders only
    ; Correctly size folder match list
    ReDim $asFolderMatchList[$asFolderMatchList[0] + 1]
    ; Copy size folder match array
    $asReturnList = $asFolderMatchList
    ; Simple sort list
    _RFLTA_ArraySort($asReturnList)
    Case 1 ; Files only
    If $sReturnPath = 0 Then ; names only so simple sort suffices
    ; Combine file match lists
    _RFLTA_AddFileLists($asReturnList, $asRootFileMatchList, $asFileMatchList)
    ; Simple sort combined file list
    _RFLTA_ArraySort($asReturnList)
    Else
    ; Combine sorted file match lists
    _RFLTA_AddFileLists($asReturnList, $asRootFileMatchList, $asFileMatchList, 1)
    EndIf
    Case 0 ; Both files and folders
    If $sReturnPath = 0 Then ; names only so simple sort suffices
    ; Combine file match lists
    _RFLTA_AddFileLists($asReturnList, $asRootFileMatchList, $asFileMatchList)
    ; Set correct count for folder add
    $asReturnList[0] += $asFolderMatchList[0]
    ; Resize and add file match array
    ReDim $asFolderMatchList[$asFolderMatchList[0] + 1]
    _RFLTA_ArrayConcatenate($asReturnList, $asFolderMatchList)
    ; Simple sort final list
    _RFLTA_ArraySort($asReturnList)
    Else
    ; Combine sorted file match lists
    _RFLTA_AddFileLists($asReturnList, $asRootFileMatchList, $asFileMatchList, 1)
    ; Add folder count
    $asReturnList[0] += $asFolderMatchList[0]
    ; Sort folder match list
    ReDim $asFolderMatchList[$asFolderMatchList[0] + 1]
    _RFLTA_ArraySort($asFolderMatchList)

    ; Now add folders in correct place
    Local $iLastIndex = $asReturnList[0]
    For $i = $asFolderMatchList[0] To 1 Step -1
    ; Find first filename containing folder name
    Local $iIndex = _RFLTA_ArraySearch($asReturnList, $asFolderMatchList[$i])
    If $iIndex = -1 Then
    ; Empty folder so insert immediately above previous
    _RFLTA_ArrayInsert($asReturnList, $iLastIndex, $asFolderMatchList[$i])
    Else
    ; Insert folder at correct point above files
    _RFLTA_ArrayInsert($asReturnList, $iIndex, $asFolderMatchList[$i])
    $iLastIndex = $iIndex
    EndIf
    Next
    EndIf
    EndSwitch

    Else ; No sort

    ; Check if any file/folders have been added
    If $asReturnList[0] = 0 Then Return SetError(1, 8, "")

    ; Remove any unused return list elements from last ReDim
    ReDim $asReturnList[$asReturnList[0] + 1]

    EndIf

    Return $asReturnList

EndFunc ;==>_RecFileListToArray

All other functions and documentation have been left alone, for Melba. Didn't want to ruin your beautiful code. :idea:

Link to comment
Share on other sites

  • Moderators

darkjohn20,

Flattery always helps: :)

Here is a simplifed version to do what you want:

#include-once

_RecFileFinder("M:\", "Your_Function", "*.au3.2.bak", "", 1)

; #FUNCTION# ====================================================================================================================
; Name...........: _RecFileFinder
; Description ...: Finds files in a specified path with optional recursion and runs a function.
; Syntax.........: _RecFileFinder($sPath, $sFunction[, $sInclude_List = "*"[, $sExclude_List = ""[, $fRecur = 0]]])
; Parameters ....: $sPath   - Initial path
;                  $sFunction - Function to call when file found
;                  $sInclude_List - Optional: the filter for included results (default is "*"). Multiple filters must be separated by ";"
;                  $sExclude_List - Optional: the filter for excluded results (default is ""). Multiple filters must be separated by ";"
;                  $fRecur  - Optional: specifies whether to search in subfolders
;                  |$fRecur= 0 (Default) Do not search in subfolders
;                  |$fRecur= 1 Search in subfolders
; Requirement(s).: v3.3.1.1 or higher
; Return values .: Success:  1
;                  Failure: 0 and @error = 1 with @extended set as follows:
;                  |1 = Path not found or invalid
;                  |2 = Invalid $sInclude_List
;                  |3 = Invalid $sExclude_List
;                  |4 = Invalid $fRecur
; Author ........: Melba23 using SRE code from forums
; Remarks .......:
; Related .......:
; Link ..........;
; Example .......; Yes
; ===============================================================================================================================
Func _RecFileFinder($sPath, $sFunction, $sInclude_List = "*", $sExclude_List = "", $fRecur = 0)

    Local $asFolderList[3] = [1], $sInclude_List_Mask, $sExclude_List_Mask
    Local $sCurrentPath, $hSearch, $sReturnPath = "", $sName, $fFolder

    ; Check valid path
    If Not FileExists($sPath) Then Return SetError(1, 1, "")
    ; Ensure trailing \
    If StringRight($sPath, 1) <> "\" Then $sPath = $sPath & "\"
    ; Add path to folder list
    $asFolderList[1] = $sPath

    ; Determine Filter mask for SRE check
    If StringRegExp($sInclude_List, "\\|/|:|\<|\>|\|") Then Return SetError(1, 2, "") ; Check for invalid characters
    $sInclude_List = StringReplace(StringStripWS(StringRegExpReplace($sInclude_List, "\s*;\s*", ";"), 3), ";", "|") ; Strip WS and swap :/|
    $sInclude_List_Mask = "(?i)^" & StringReplace(StringReplace(StringReplace($sInclude_List, ".", "\."), "*", ".*"), "?", ".") & "\z" ; Convert to SRE pattern

    ; Determine Exclude mask for SRE check
    If $sExclude_List = "" Then
        $sExclude_List_Mask = ":" ; Set unmatchable mask
    Else
        If StringRegExp($sExclude_List, "\\|/|:|\<|\>|\|") Then Return SetError(1, 3, "") ; Check for invalid characters
        $sExclude_List = StringReplace(StringStripWS(StringRegExpReplace($sExclude_List, "\s*;\s*", ";"), 3), ";", "|") ; Strip WS and swap ;/|
        $sExclude_List_Mask = "(?i)^" & StringReplace(StringReplace(StringReplace($sInclude_List, ".", "\."), "*", ".*"), "?", ".") & "\z" ; Convert to SRE pattern
    EndIf

    ; Verify other parameter values
    If Not ($fRecur = 0 Or $fRecur = 1) Then Return SetError(1, 4, "")

    ; Search in listed folders
    While $asFolderList[0] > 0

        ; Set path to search
        $sCurrentPath = $asFolderList[$asFolderList[0]]
        ; Reduce folder array count
        $asFolderList[0] -= 1
        ; Get search handle
        $hSearch = FileFindFirstFile($sCurrentPath & "*")
        ; If folder empty move to next in list
        If $hSearch = -1 Then ContinueLoop

        ; Search folder
        While 1
            $sName = FileFindNextFile($hSearch)
            ; Check for end of folder
            If @error Then ExitLoop
            ; Check for subfolder - @extended set in 3.3.1.1 +
            $fFolder = @extended
            ;$fFolder = StringInStr(FileGetAttrib($sCurrentPath & $sName), "D") ; pre 3.3.1.1

            ; If recursive search, add subfolder to folder list
            If $fRecur And $fFolder Then
                ; Increase folder array count
                $asFolderList[0] += 1
                ; Double folder array size if too small (fewer ReDim needed)
                If UBound($asFolderList) <= $asFolderList[0] + 1 Then ReDim $asFolderList[UBound($asFolderList) * 2]
                ; Add subfolder to list
                $asFolderList[$asFolderList[0]] = $sCurrentPath & $sName & "\"
            EndIf

            ; Check file/folder type against required return value and file/folder name against Include/Exclude masks
            If Not $fFolder And StringRegExp($sName, $sInclude_List_Mask) And Not StringRegExp($sName, $sExclude_List_Mask) Then

                ;This is where you can do what you want with the found files
                MsgBox(0, "Result", "Found: " & $sCurrentPath & $sName & @CRLF & @CRLF & "Now running: " & $sFunction)

            EndIf
        WEnd

        ; Close current search
        FileClose($hSearch)

    WEnd

EndFunc   ;==>_RecFileFinder

I hope that does what you want. :idea:

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

I modified it a small bit to better fit my needs. This does files and folders, and tells the function which it is.

#include-once

_RecFileFinder(@HomeDrive & "\", "_Found", "*", "", 1)

Func _Found($Path, $IsFolder)
    Select
        Case $IsFolder
            ConsoleWrite($Path & "\" & @CRLF)
        Case Else
            ;ConsoleWrite($Path & @CRLF)
    EndSelect
EndFunc

; #FUNCTION# ====================================================================================================================
; Name...........: _RecFileFinder
; Description ...: Finds files in a specified path with optional recursion and runs a function.
; Syntax.........: _RecFileFinder($sPath, $sFunction[, $sInclude_List = "*"[, $sExclude_List = ""[, $fRecur = 0]]])
; Parameters ....: $sPath - Initial path
;   $sFunction - Function to call when file found
;   $sInclude_List - Optional: the filter for included results (default is "*"). Multiple filters must be separated by ";"
;   $sExclude_List - Optional: the filter for excluded results (default is ""). Multiple filters must be separated by ";"
;   $fRecur - Optional: specifies whether to search in subfolders
;   |$fRecur= 0 (Default) Do not search in subfolders
;   |$fRecur= 1 Search in subfolders
; Requirement(s).: v3.3.1.1 or higher
; Return values .: Success: 1
;   Failure: 0 and @error = 1 with @extended set as follows:
;   |1 = Path not found or invalid
;   |2 = Invalid $sInclude_List
;   |3 = Invalid $sExclude_List
;   |4 = Invalid $fRecur
; Author ........: Melba23 using SRE code from forums
; Remarks .......:
; Related .......:
; Link ..........;
; Example .......; Yes
; ===============================================================================================================================
Func _RecFileFinder($sPath, $sFunction, $sInclude_List = "*", $sExclude_List = "", $fRecur = 0)

    Local $asFolderList[3] = [1], $sInclude_List_Mask, $sExclude_List_Mask
    Local $sCurrentPath, $hSearch, $sReturnPath = "", $sName, $fFolder

    ; Check valid path
    If Not FileExists($sPath) Then Return SetError(1, 1, "")
    ; Ensure trailing \
    If StringRight($sPath, 1) <> "\" Then $sPath = $sPath & "\"
    ; Add path to folder list
    $asFolderList[1] = $sPath

    ; Determine Filter mask for SRE check
    If StringRegExp($sInclude_List, "\\|/|:|\<|\>|\|") Then Return SetError(1, 2, "") ; Check for invalid characters
    $sInclude_List = StringReplace(StringStripWS(StringRegExpReplace($sInclude_List, "\s*;\s*", ";"), 3), ";", "|") ; Strip WS and swap :/|
    $sInclude_List_Mask = "(?i)^" & StringReplace(StringReplace(StringReplace($sInclude_List, ".", "\."), "*", ".*"), "?", ".") & "\z" ; Convert to SRE pattern

    ; Determine Exclude mask for SRE check
    If $sExclude_List = "" Then
    $sExclude_List_Mask = ":" ; Set unmatchable mask
    Else
    If StringRegExp($sExclude_List, "\\|/|:|\<|\>|\|") Then Return SetError(1, 3, "") ; Check for invalid characters
    $sExclude_List = StringReplace(StringStripWS(StringRegExpReplace($sExclude_List, "\s*;\s*", ";"), 3), ";", "|") ; Strip WS and swap ;/|
    $sExclude_List_Mask = "(?i)^" & StringReplace(StringReplace(StringReplace($sInclude_List, ".", "\."), "*", ".*"), "?", ".") & "\z" ; Convert to SRE pattern
    EndIf

    ; Verify other parameter values
    If Not ($fRecur = 0 Or $fRecur = 1) Then Return SetError(1, 4, "")

    ; Search in listed folders
    While $asFolderList[0] > 0

    ; Set path to search
    $sCurrentPath = $asFolderList[$asFolderList[0]]
    ; Reduce folder array count
    $asFolderList[0] -= 1
    ; Get search handle
    $hSearch = FileFindFirstFile($sCurrentPath & "*")
    ; If folder empty move to next in list
    If $hSearch = -1 Then ContinueLoop

    ; Search folder
    While 1
    $sName = FileFindNextFile($hSearch)
    ; Check for end of folder
    If @error Then ExitLoop
    ; Check for subfolder - @extended set in 3.3.1.1 +
    $fFolder = @extended
    ;$fFolder = StringInStr(FileGetAttrib($sCurrentPath & $sName), "D") ; pre 3.3.1.1

    ; If recursive search, add subfolder to folder list
    If $fRecur And $fFolder Then
    ; Increase folder array count
    $asFolderList[0] += 1
    ; Double folder array size if too small (fewer ReDim needed)
    If UBound($asFolderList) <= $asFolderList[0] + 1 Then ReDim $asFolderList[UBound($asFolderList) * 2]
    ; Add subfolder to list
    $asFolderList[$asFolderList[0]] = $sCurrentPath & $sName & "\"
                Call($sFunction, $sCurrentPath & $sName, 1)
    EndIf

    ; Check file/folder type against required return value and file/folder name against Include/Exclude masks
    If Not $fFolder And StringRegExp($sName, $sInclude_List_Mask) And Not StringRegExp($sName, $sExclude_List_Mask) Then

    ;This is where you can do what you want with the found files
    Call($sFunction, $sCurrentPath & $sName, 0)

    EndIf
    WEnd

    ; Close current search
    FileClose($hSearch)

    WEnd

EndFunc ;==>_RecFileFinder

Is using $IsFolder a better method than say, seeing if it has an extension or not in the called function?

Link to comment
Share on other sites

  • Moderators

darkjohn20,

Is using $IsFolder a better method than say, seeing if it has an extension or not in the called function?

It would depend on how you set the filters. I can see nothing "wrong" with how you have done it, assuming you want to do different things to folders and files. In my experience it is usually best to avoid "clever" solutions and use the KISS* principle. :idea:

M23

* Keep It Simple, Stupid!

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Alright, I just wondered if you had any suggestions, being the writer of this. :idea:

Thanks again!

Also, is there a different StringRegExp pattern for folders? When I try to exclude "$Recycle.bin", the search returns immediately when I use this line:

; If recursive search, add subfolder to folder list
If $fRecur And $fFolder And StringRegExp($sName, $sInclude_List_Mask) And Not StringRegExp($sName, $sExclude_List_Mask) Then
Edited by darkjohn20
Link to comment
Share on other sites

  • Moderators

darkjohn20,

You learn something everyday! "$" is a reserved sign within the SRE syntax and needs to be escaped to match a literal "$" in the target string. The current code did not do this and so failed when faced with the "$Recycle.bin" string.

Try this version (I have also corrected a stupid "copy/paste" error that was in the code above :idea: ):

#include-once

_RecFileFinder(@HomeDrive & "\", "_Found", "*", "$Recycle.Bin", 1)

Func _Found($Path, $IsFolder)
    Select
        Case $IsFolder
            ConsoleWrite($Path & "\" & @CRLF)
        Case Else
            ;ConsoleWrite($Path & @CRLF)
    EndSelect
EndFunc   ;==>_Found

; #FUNCTION# ====================================================================================================================
; Name...........: _RecFileFinder
; Description ...: Finds files in a specified path with optional recursion and runs a function.
; Syntax.........: _RecFileFinder($sPath, $sFunction[, $sInclude_List = "*"[, $sExclude_List = ""[, $fRecur = 0]]])
; Parameters ....: $sPath - Initial path
;   $sFunction - Function to call when file found
;   $sInclude_List - Optional: the filter for included results (default is "*"). Multiple filters must be separated by ";"
;   $sExclude_List - Optional: the filter for excluded results (default is ""). Multiple filters must be separated by ";"
;   $fRecur - Optional: specifies whether to search in subfolders
;   |$fRecur= 0 (Default) Do not search in subfolders
;   |$fRecur= 1 Search in subfolders
; Requirement(s).: v3.3.1.1 or higher
; Return values .: Success: 1
;   Failure: 0 and @error = 1 with @extended set as follows:
;   |1 = Path not found or invalid
;   |2 = Invalid $sInclude_List
;   |3 = Invalid $sExclude_List
;   |4 = Invalid $fRecur
; Author ........: Melba23 using SRE code from forums
; Remarks .......:
; Related .......:
; Link ..........;
; Example .......; Yes
; ===============================================================================================================================
Func _RecFileFinder($sPath, $sFunction, $sInclude_List = "*", $sExclude_List = "", $fRecur = 0)

    Local $asFolderList[3] = [1], $sInclude_List_Mask, $sExclude_List_Mask
    Local $sCurrentPath, $hSearch, $sReturnPath = "", $sName, $fFolder

    ; Check valid path
    If Not FileExists($sPath) Then Return SetError(1, 1, "")
    ; Ensure trailing \
    If StringRight($sPath, 1) <> "\" Then $sPath = $sPath & "\"
    ; Add path to folder list
    $asFolderList[1] = $sPath

    ; Determine Filter mask for SRE check
    If StringRegExp($sInclude_List, "\\|/|:|\<|\>|\|") Then Return SetError(1, 2, "") ; Check for invalid characters
    $sInclude_List = StringReplace(StringStripWS(StringRegExpReplace($sInclude_List, "\s*;\s*", ";"), 3), ";", "|") ; Strip WS and swap :/|
    $sInclude_List_Mask = "(?i)^" & StringReplace(StringReplace(StringReplace(StringReplace($sInclude_List, "$", "\$"), ".", "\."), "*", ".*"), "?", ".") & "\z" ; Convert to SRE pattern

    ; Determine Exclude mask for SRE check
    If $sExclude_List = "" Then
        $sExclude_List_Mask = ":" ; Set unmatchable mask
    Else
        If StringRegExp($sExclude_List, "\\|/|:|\<|\>|\|") Then Return SetError(1, 3, "") ; Check for invalid characters
        $sExclude_List = StringReplace(StringStripWS(StringRegExpReplace($sExclude_List, "\s*;\s*", ";"), 3), ";", "|") ; Strip WS and swap ;/|
        $sExclude_List_Mask = "(?i)^" & StringReplace(StringReplace(StringReplace(StringReplace($sExclude_List, "$", "\$"), ".", "\."), "*", ".*"), "?", ".") & "\z" ; Convert to SRE pattern
    EndIf

    ; Verify other parameter values
    If Not ($fRecur = 0 Or $fRecur = 1) Then Return SetError(1, 4, "")

    ; Search in listed folders
    While $asFolderList[0] > 0

        ; Set path to search
        $sCurrentPath = $asFolderList[$asFolderList[0]]
        ; Reduce folder array count
        $asFolderList[0] -= 1
        ; Get search handle
        $hSearch = FileFindFirstFile($sCurrentPath & "*")
        ; If folder empty move to next in list
        If $hSearch = -1 Then ContinueLoop

        ; Search folder
        While 1
            $sName = FileFindNextFile($hSearch)
            ; Check for end of folder
            If @error Then ExitLoop
            ; Check for subfolder - @extended set in 3.3.1.1 +
            $fFolder = @extended
            ;$fFolder = StringInStr(FileGetAttrib($sCurrentPath & $sName), "D") ; pre 3.3.1.1

            ; If recursive search, add subfolder to folder list
            If $fRecur And $fFolder Then
                ; Increase folder array count
                $asFolderList[0] += 1
                ; Double folder array size if too small (fewer ReDim needed)
                If UBound($asFolderList) <= $asFolderList[0] + 1 Then ReDim $asFolderList[UBound($asFolderList) * 2]
                ; Add subfolder to list
                $asFolderList[$asFolderList[0]] = $sCurrentPath & $sName & "\"
                If StringRegExp($sName, $sInclude_List_Mask) And Not StringRegExp($sName, $sExclude_List_Mask) Then
                    Call($sFunction, $sCurrentPath & $sName, 1)
                EndIf
            EndIf

            ; Check file/folder type against required return value and file/folder name against Include/Exclude masks
            If Not $fFolder And StringRegExp($sName, $sInclude_List_Mask) And Not StringRegExp($sName, $sExclude_List_Mask) Then
                ;This is where you can do what you want with the found files
                Call($sFunction, $sCurrentPath & $sName, 0)
            EndIf
        WEnd

        ; Close current search
        FileClose($hSearch)

    WEnd

EndFunc   ;==>_RecFileFinder

That works for me now and properly excludes $Recycle.Bin - please test it and let me know if it does for you. :(

Thanks for the bug report - I will now investigate what else might need to be escaped! :)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

I forgot to mention that I also just tried "recycle.bin". New version seems to work great! Thanks for all of the help.:idea:

Edit: I finally see the effects of StringRegExp being used quickly. :)

Edited by darkjohn20
Link to comment
Share on other sites

  • Moderators

darkjohn20,

That was quick! I hope you have not been up all night waiting for my reply! :idea:

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Nope, it's 1 in the afternoon and I was just playing games :idea:.

I modified the code a little in hopes to speed performance. Here's what I have:

Func _RecFileFinder($sPath, $sFunction, $sInclude_List = "*", $sExclude_List = "", $fRecur = 0)

    Local $asFolderList[3] = [1], $sInclude_List_Mask, $sExclude_List_Mask
    Local $sCurrentPath, $hSearch, $sReturnPath = "", $sName, $fFolder

    ; Check valid path
    If Not FileExists($sPath) Then Return SetError(1, 1, "")
    ; Ensure trailing \
    If StringRight($sPath, 1) <> "\" Then $sPath = $sPath & "\"
    ; Add path to folder list
    $asFolderList[1] = $sPath

    ; Determine Filter mask for SRE check
    If StringRegExp($sInclude_List, "\\|/|:|\<|\>|\|") Then Return SetError(1, 2, "") ; Check for invalid characters
    $sInclude_List = StringReplace(StringStripWS(StringRegExpReplace($sInclude_List, "\s*;\s*", ";"), 3), ";", "|") ; Strip WS and swap :/|
    $sInclude_List_Mask = "(?i)^" & StringReplace(StringReplace(StringReplace(StringReplace($sInclude_List, "{:content:}quot;, "\{:content:}quot;), ".", "\."), "*", ".*"), "?", ".") & "\z" ; Convert to SRE pattern

    ; Determine Exclude mask for SRE check
    If $sExclude_List = "" Then
    $sExclude_List_Mask = ":" ; Set unmatchable mask
    Else
    If StringRegExp($sExclude_List, "\\|/|:|\<|\>|\|") Then Return SetError(1, 3, "") ; Check for invalid characters
    $sExclude_List = StringReplace(StringStripWS(StringRegExpReplace($sExclude_List, "\s*;\s*", ";"), 3), ";", "|") ; Strip WS and swap ;/|
    $sExclude_List_Mask = "(?i)^" & StringReplace(StringReplace(StringReplace(StringReplace($sExclude_List, "{:content:}quot;, "\{:content:}quot;), ".", "\."), "*", ".*"), "?", ".") & "\z" ; Convert to SRE pattern
    EndIf

    ; Verify other parameter values
    If Not ($fRecur = 0 Or $fRecur = 1) Then Return SetError(1, 4, "")

    ; Search in listed folders
    While $asFolderList[0] > 0

    ; Set path to search
    $sCurrentPath = $asFolderList[$asFolderList[0]]
    ; Reduce folder array count
    $asFolderList[0] -= 1
    ; Get search handle
    $hSearch = FileFindFirstFile($sCurrentPath & "*")
    ; If folder empty move to next in list
    If $hSearch = -1 Then ContinueLoop

    ; Search folder
    While 1
    $sName = FileFindNextFile($hSearch)
    ; Check for end of folder
    If @error Then ExitLoop
    ; Check for subfolder - @extended set in 3.3.1.1 +
    $fFolder = @extended
    ;$fFolder = StringInStr(FileGetAttrib($sCurrentPath & $sName), "D") ; pre 3.3.1.1

    ; If recursive search, add subfolder to folder list
            If StringRegExp($sName, $sInclude_List_Mask) And Not StringRegExp($sName, $sExclude_List_Mask) Then
                If $fRecur And $fFolder Then
                    ; Increase folder array count
                    $asFolderList[0] += 1
                    ; Double folder array size if too small (fewer ReDim needed)
                    If UBound($asFolderList) <= $asFolderList[0] + 1 Then ReDim $asFolderList[UBound($asFolderList) * 2]
                    ; Add subfolder to list
                    $asFolderList[$asFolderList[0]] = $sCurrentPath & $sName & "\"

                    Call($sFunction, $sCurrentPath & $sName, 1)
                Else
                    Call($sFunction, $sCurrentPath & $sName, 0)
                EndIf
    EndIf
    WEnd

    ; Close current search
    FileClose($hSearch)
    WEnd

EndFunc

Instead of 2 If...Then statements with StringRegExp, there's only one. Same with checking whether it's a folder or not. Used Else.

Formatting is a bit messed up.

Edited by darkjohn20
Link to comment
Share on other sites

  • Moderators

darkjohn20,

That will not work for recursive file searches. :)

If you are looking for, say, *.dat files then using your version will exclude any folders that do not match that mask - which will probably be all of them - from the recursive search!

You:

Check masks

    If folder do things if required
        
    If file do things if required
        

Me:

If folder add to list to search
    
    Now check folder against masks and do things if required
    
If file check masks and do things if required

Is that clear enough? :idea:

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

You've a bug in your exclude edit routine, as you mistakenly reference $sIncludeList rather than $sExcludeList.

The include and exclude edits aren't handling files with more than one period "." in them either.

You might be able to incorporate some of the edits from the very similar routines in this thread from last July:

Improvement of included _FileListToArray function.

Link to comment
Share on other sites

  • Moderators

Spiff59,

you mistakenly reference $sIncludeList rather than $sExcludeList

That was the "stupid "copy/paste" error" I referred to. :)

The [..] edits aren't handling files with more than one period "." in them either

I am afraid I do not follow what you mean - could you please explain further? As far as I can see all "." in List are changed to "\." in List_Mask so that they are escaped. :idea:

darkjohn20,

This is what I have come up with to date to get over the SRE literals ($ and ^):

$s##clude_List_Mask = "(?i)^" & StringReplace(StringReplace(StringRegExpReplace($s##clude_List, "([\^|\$|\.])", "\\$1"), "*", ".*"), "?", ".") & "\z" ; Convert to SRE pattern

Remember that you need to change both the Include and Exclude lines - and change the ## into the correct In/Ex form! :(

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Would THIS be correct?:

; Search folder
    While 1
    $sName = FileFindNextFile($hSearch)
    ; Check for end of folder
    If @error Then ExitLoop
    ; Check for subfolder - @extended set in 3.3.1.1 +
    $fFolder = @extended
            $iStringRegExp = StringRegExp($sName, $sInclude_List_Mask)
            $eStringRegExp = StringRegExp($sName, $sExclude_List_Mask)

    ; If recursive search, add subfolder to folder list
    If $fRecur And $fFolder Then
    ; Increase folder array count
    $asFolderList[0] += 1
    ; Double folder array size if too small (fewer ReDim needed)
    If UBound($asFolderList) <= $asFolderList[0] + 1 Then ReDim $asFolderList[UBound($asFolderList) * 2]
    ; Add subfolder to list
    $asFolderList[$asFolderList[0]] = $sCurrentPath & $sName & "\"

    If $iStringRegExp And Not $eStringRegExp Then ;Folder found
    Call($sFunction, $sCurrentPath & $sName, 1)
    EndIf
            ElseIf Not $fFolder And $iStringRegExp And Not $eStringRegExp Then ;File found
    Call($sFunction, $sCurrentPath & $sName, 0)
    EndIf
    WEnd

And thanks, I fixed those two lines.

Link to comment
Share on other sites

  • Moderators

darkjohn20,

No, but I think this might be: :idea:

; Search folder
While 1
    $sName = FileFindNextFile($hSearch)
    ; Check for end of folder
    If @error Then ExitLoop
    ; Check for subfolder - @extended set in 3.3.1.1 +
    $fFolder = @extended
    ; If recursive search, add subfolder to folder list
    If $fRecur And $fFolder Then
        ; Increase folder array count
        $asFolderList[0] += 1
        ; Double folder array size if too small (fewer ReDim needed)
        If UBound($asFolderList) <= $asFolderList[0] + 1 Then ReDim $asFolderList[UBound($asFolderList) * 2]
        ; Add subfolder to list
        $asFolderList[$asFolderList[0]] = $sCurrentPath & $sName & "\"
    EndIf

    If StringRegExp($sName, $sInclude_List_Mask) And Not StringRegExp($sName, $sExclude_List_Mask) Then
        Call($sFunction, $sCurrentPath & $sName, $fFolder)
    EndIf
WEnd

Your version would have failed if the $fRecur parameter was not set - no folders would have been returned. The earlier versions were based on some code looking for files only - hence the name RecFILEFinder - this version finds both files and folders with the $fFolder flag telling your function what the returned name actually is.

I think we might have got there finally - sorry about the detours along the way! :)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

I am afraid I do not follow what you mean - could you please explain further? As far as I can see all "." in List are changed to "\." in List_Mask so that they are escaped. :idea:

M23

Try this, it's the nearly identical routine I referenced in the above thread, and yours running beside it.

With an exclude of, for instance, "*.exe" yours will drop a file named "xxx.exe.config", the other routine with slightly different edits does not.

#include<array.au3>
#include<file.au3>
;$Path = @SystemDir
;$Path = "C:\Program Files\Autoit3"
$Path = "C:\Windows"
$SkipFolderList = ""
;$SkipFolderList = "System32;$*"
$IncludeList = "*"
;$IncludeList = "A*;S.*;*.*.*;*.ico"
;$ExcludeList = ""
$ExcludeList = "*.exe;*.dll*"
$ReturnType = 1; 0 = files+folders, 1 = files only, 2 = folders only
$ReturnFormat = 0; 2 = file/folder name only , 1 = relative path, 2 = full path
$Recursive = 1

$repeat = 10

$timer = TimerInit()
For $j = 1 to $repeat
    $x1= _FileListToArrayZ($Path, $SkipFolderList, $IncludeList, $ExcludeList, $ReturnType, $ReturnFormat, $Recursive)
Next
$t1 = TimerDiff ($timer)
_ArrayDisplay($x1,"ver1")

$ReturnFormat = 2; 0 = Initial path not included, 1 =  Initial path included, 2 =  File/folder name only
$timer = TimerInit()
For $j = 1 to $repeat
   $x2 = _RecFileListToArray($Path, $IncludeList, $ReturnType, $Recursive, $ExcludeList, $ReturnFormat)
Next
$t2 = TimerDiff ($timer)
_ArrayDisplay($x2,"ver2")

MsgBox (0, "", "$iReturnType = " & $ReturnType & @CRLF &"Ver1:  " & Int($t1/10)/100 & @CRLF & "Ver2:  " & Int($t2/10)/100)

;===============================================================================
Func _FileListToArrayZ($sPath, $sExcludeFolderList = "", $sIncludeList = "*", $sExcludeList = "", $iReturnType = 0, $iReturnFormat = 0, $bRecursive = False)
    Local $sRet = "", $sReturnFormat = ""

    ; Edit include path (strip trailing slashes, and append single slash)
    $sPath = StringRegExpReplace($sPath, "[\\/]+\z", "") & "\"
    If Not FileExists($sPath) Then Return SetError(1, 1, "")

    ; Edit exclude folders list
    If $sExcludeFolderList Then
        ; Strip leading/trailing spaces and semi-colons, any adjacent semi-colons, and spaces surrounding semi-colons
        $sExcludeFolderList = StringRegExpReplace(StringRegExpReplace($sExcludeFolderList, "(\s*;\s*)+", ";"), "\A;|;\z", "")
        ; Convert to Regular Expression, step 1: Wrap brackets around . and $ (what other characters needed?)
        $sExcludeFolderList = StringRegExpReplace($sExcludeFolderList, '[.$]', '\[\0\]')
        ; Convert to Regular Expression, step 2: Convert '?' to '.', and '*' to '.*?'
        $sExcludeFolderList = StringReplace(StringReplace($sExcludeFolderList, "?", "."), "*", ".*?")
        ; Convert to Regular Expression, step 3; case-insensitive, convert ';' to '|', match from first char, terminate strings
        $sExcludeFolderList = "(?i)\A(?!" & StringReplace($sExcludeFolderList, ";", "$|")  & "$)"
    EndIf

    ; Edit include files list
    If $sIncludeList ="*" Then
        $sIncludeList = ""
    Else
        If StringRegExp($sIncludeList, "[\\/ :> <\|]|(?s)\A\s*\z") Then Return SetError(2, 2, "")
        ; Strip leading/trailing spaces and semi-colons, any adjacent semi-colons, and spaces surrounding semi-colons
        $sIncludeList = StringRegExpReplace(StringRegExpReplace($sIncludeList, "(\s*;\s*)+", ";"), "\A;|;\z", "")
        ; Convert to Regular Expression, step 1: Wrap brackets around . and $ (what other characters needed?)
        $sIncludeList = StringRegExpReplace($sIncludeList, '[.$]', '\[\0\]')
        ; Convert to Regular Expression, step 2: Convert '?' to '.', and '*' to '.*?'
        $sIncludeList = StringReplace(StringReplace($sIncludeList, "?", "."), "*", ".*?")
        ; Convert to Regular Expression, step 3; case-insensitive, convert ';' to '|', match from first char, terminate strings
        $sIncludeList = "(?i)\A(" & StringReplace($sIncludeList, ";", "$|")  & "$)"
    EndIf

    ; Edit exclude files list
    If $sExcludeList Then
        ; Strip leading/trailing spaces and semi-colons, any adjacent semi-colons, and spaces surrounding semi-colons
        $sExcludeList = StringRegExpReplace(StringRegExpReplace($sExcludeList, "(\s*;\s*)+", ";"), "\A;|;\z", "")
        ; Convert to Regular Expression, step 1: Wrap brackets around . and $ (what other characters needed?)
        $sExcludeList = StringRegExpReplace($sExcludeList, '[.$]', '\[\0\]')
        ; Convert to Regular Expression, step 2: Convert '?' to '.', and '*' to '.*?'
        $sExcludeList = StringReplace(StringReplace($sExcludeList, "?", "."), "*", ".*?")
        ; Convert to Regular Expression, step 3; case-insensitive, convert ';' to '|', match from first char, terminate strings
        $sExcludeList = "(?i)\A(?!" & StringReplace($sExcludeList, ";", "$|")  & "$)"
    EndIf

;   MsgBox(1,"Masks","File include: " & $sIncludeList & @CRLF & "File exclude: " & $ExcludeList & @CRLF _
;           & "Dir include : " & $FolderInclude & @CRLF & "Dir exclude : " & $ExcludeFolderList)

    If Not ($iReturnType = 0 Or $iReturnType = 1 Or $iReturnType = 2) Then Return SetError(3, 3, "")

    Local $sOrigPathLen = StringLen($sPath), $aQueue[64] = [1,$sPath], $iQMax = 63
    While $aQueue[0]
        $WorkFolder = $aQueue[$aQueue[0]]
        $aQueue[0] -= 1
        $search = FileFindFirstFile($WorkFolder & "*")
        If @error Then ContinueLoop
        Switch $iReturnFormat
            Case 1 ; relative path
                $sReturnFormat = StringTrimLeft($WorkFolder, $sOrigPathLen)
            Case 2 ; full path
                $sReturnFormat = $WorkFolder
        EndSwitch
        While 1
            $file = FileFindNextFile($search)
            If @error Then ExitLoop
            If @extended Then ; Folder
                If $sExcludeFolderList And Not StringRegExp($file, $sExcludeFolderList) Then ContinueLoop
                If $bRecursive Then
                    If $aQueue[0] = $iQMax Then
                        $iQMax += 128
                        ReDim $aQueue[$iQMax + 1]
                    EndIf
                    $aQueue[0] += 1
                    $aQueue[$aQueue[0]] = $WorkFolder & $file & "\"
                EndIf
                If $iReturnType = 1 Then ContinueLoop
            Else ; File
                If $iReturnType = 2 Then ContinueLoop
            EndIf
            If $sIncludeList And Not StringRegExp($file, $sIncludeList) Then ContinueLoop
            If $sExcludeList And Not StringRegExp($file, $sExcludeList) Then ContinueLoop
            $sRet &= $sReturnFormat & $file & "|"
        WEnd
        FileClose($search)
    WEnd
    If Not $sRet Then Return SetError(4, 4, "")
    Return StringSplit(StringTrimRight($sRet, 1), "|")
EndFunc


;===============================================================================
; #FUNCTION# ====================================================================================================================
; Name...........: _RecFileListToArray
; Description ...: Lists files and\or folders in a specified path with optional recursion.  Compatible with existing _FileListToArray syntax
; Syntax.........: _RecFileListToArray($sPath[, $sInclude_List = "*"[, $iReturn = 0[, $fRecur = 0[, $sExclude_List = ""[, $iFullPath = 0]]]]])
; Parameters ....: $sPath   - Initial path used to generate filelist
;                  $sInclude_List - Optional: the filter for included results (default is "*"). Multiple filters must be separated by ";"
;                  $iReturn   - Optional: specifies whether to return files, folders or both
;                  |$iReturn=0 (Default) Return both files and folders
;                  |$iReturn=1 Return files only
;                  |$iReturn=2 Return folders only
;                  $fRecur  - Optional: specifies whether to search in subfolders
;                  |$fRecur=0 (Default) Do not search in subfolders
;                  |$fRecur=1 Search in subfolders
;                  $sExclude_List - Optional: the filter for excluded results (default is ""). Multiple filters must be separated by ";"
;                  $iFullPath  - Optional: specifies path of result string
;                  |$iFullPath=0 (Default) Initial path not included
;                  |$iFullPath=1 Initial path included
;                  |$iFullPath=2 File/folder name only
; Requirement(s).: v3.3.1.1 or higher
; Return values .: Success:  One-dimensional array made up as follows:
;                  |$array[0] = Number of Files\Folders returned
;                  |$array[1] = 1st File\Folder
;                  |$array[2] = 2nd File\Folder
;                  |...
;                  |$array[n] = nth File\Folder
;                  Failure: Null string and @error = 1 with @extended set as follows:
;                  |1 = Path not found or invalid
;                  |2 = Invalid $sInclude_List
;                  |3 = Invalid $iReturn
;                  |4 = Invalid $fRecur
;                  |5 = Invalid $sExclude_List
;                  |6 = Invalid $iFullPath
;                  |7 = No files/folders found
; Author ........: Melba23 using SRE code from forums
; Remarks .......:
; Related .......:
; Link ..........;
; Example .......; Yes
; ===============================================================================================================================
Func _RecFileListToArray($sInitialPath, $sInclude_List = "*", $iReturn = 0, $fRecur = 0, $sExclude_List = "", $iFullPath = 0)

    Local $asReturnList[1] = [0], $asFolderList[3] = [1], $sInclude_List_Mask, $sExclude_List_Mask
    Local $sCurrentPath, $hSearch, $sReturnPath = "", $sName, $fFolder

    ; Check valid path
    If Not FileExists($sInitialPath) Then Return SetError(1, 1, "")
    ; Ensure trailing \
    If StringRight($sInitialPath, 1) <> "\" Then $sInitialPath = $sInitialPath & "\"
    ; Add path to folder list
    $asFolderList[1] = $sInitialPath

    ; Determine Filter mask for SRE check
    If StringRegExp($sInclude_List, "\\|/|:|\<|\>|\|") Then Return SetError(1, 2, "") ; Check for invalid characters
    $sInclude_List = StringReplace(StringStripWS(StringRegExpReplace($sInclude_List, "\s*;\s*", ";"), 3), ";", "|") ; Strip WS and swap :/|
    $sInclude_List_Mask = "(?i)^" & StringReplace(StringReplace(StringReplace($sInclude_List, ".", "\."), "*", ".*"), "?", ".") & "\z" ; Convert to SRE pattern

    ; Determine Exclude mask for SRE check
    If $sExclude_List = "" Then
        $sExclude_List_Mask = ":" ; Set unmatchable mask
    Else
        If StringRegExp($sExclude_List, "\\|/|:|\<|\>|\|") Then Return SetError(1, 5, "") ; Check for invalid characters
        $sExclude_List = StringReplace(StringStripWS(StringRegExpReplace($sExclude_List, "\s*;\s*", ";"), 3), ";", "|") ; Strip WS and swap ;/|
        $sExclude_List_Mask = "(?i)^" & StringReplace(StringReplace(StringReplace($sExclude_List, ".", "\."), "*", ".*"), "?", ".") & "\z" ; Convert to SRE pattern
    EndIf


    ; Verify other parameter values
    If Not ($iReturn = 0 Or $iReturn = 1 Or $iReturn = 2) Then Return SetError(1, 3, "")
    If Not ($fRecur = 0 Or $fRecur = 1) Then Return SetError(1, 4, "")
    If Not ($iFullPath = 0 Or $iFullPath = 1 Or $iFullPath = 2) Then Return SetError(1, 6, "")

    ; Search in listed folders
    While $asFolderList[0] > 0

        ; Set path to search
        $sCurrentPath = $asFolderList[$asFolderList[0]]
        ; Reduce folder array count
        $asFolderList[0] -= 1
        ; Get search handle
        $hSearch = FileFindFirstFile($sCurrentPath & "*")
        ; If folder empty move to next in list
        If $hSearch = -1 Then ContinueLoop

        ; Determine path to add to file/folder name
        Switch $iFullPath
            Case 0 ; Initial path not included
                $sReturnPath = StringReplace($sCurrentPath, $sInitialPath, "")
            Case 1 ; Initial path included
                $sReturnPath = $sCurrentPath
            ; Case 2 ; Name only so leave as ""
        EndSwitch

        ; Search folder
        While 1
            $sName = FileFindNextFile($hSearch)
            ; Check for end of folder
            If @error Then ExitLoop
            ; Check for subfolder - @extended set in 3.3.1.1 +
            $fFolder = @extended

            ; If recursive search, add subfolder to folder list
            If $fRecur And $fFolder Then
                ; Increase folder array count
                $asFolderList[0] += 1
                ; Double folder array size if too small (fewer ReDim needed)
                If UBound($asFolderList) <= $asFolderList[0] + 1 Then ReDim $asFolderList[UBound($asFolderList) * 2]
                ; Add subfolder to list
                $asFolderList[$asFolderList[0]] = $sCurrentPath & $sName & "\"
            EndIf

            ; Check file/folder type against required return value and file/folder name against Include/Exclude masks
            If $fFolder + $iReturn <> 2 And StringRegExp($sName, $sInclude_List_Mask) And Not StringRegExp($sName, $sExclude_List_Mask) Then
                ; Increase return array count
                $asReturnList[0] += 1
                ; Double return array size if too small (fewer ReDim needed)
                If UBound($asReturnList) <= $asReturnList[0] Then ReDim $asReturnList[UBound($asReturnList) * 2]
                ; Add required path to file/folder name and add to array
                $asReturnList[$asReturnList[0]] = $sReturnPath & $sName
            EndIf
        WEnd

        ; Close current search
        FileClose($hSearch)

    WEnd

    ; Check if any file/folders to return
    If $asReturnList[0] = 0 Then Return SetError(1, 7, "")
    ; Remove unused return array elements from last ReDim
    ReDim $asReturnList[$asReturnList[0] + 1]

    Return $asReturnList

EndFunc   ;==>_RecFileListToArray
Edited by Spiff59
Link to comment
Share on other sites

  • Moderators

darkjohn20,

My mistake - a surplus to requirements pair of [ ] in the SRE pattern were screwing up the result. SREs make my head hurt too much! :idea:

$s##clude_List_Mask = "(?i)^" & StringReplace(StringReplace(StringRegExpReplace($s##clude_List, "(\^|\$|\.)", "\\$1"), "*", ".*"), "?", ".") & "\z" ; Convert to SRE pattern

Try that - it should work now. :)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Seems to work. I may modify it a bit, because while it excludes "C:\Windows\", it includes any folders IN "C:\Windows\". For files this is ok, but when I'm only searching for folders, I don't want it to continue inside an excluded path.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...