Jump to content

Recommended Posts

I know there's already several of these types of functions around the forum but there were some things I wanted to do different, so I wrote my own.

In the tests I've done this appears to be working fine, but I'd appreciate a second look.

The error returns and the first three parameters are the same as the vanilla _FileListToArray, but there are a couple new flags, and two new parameters.

The new flags include:

- enabling recursion (4)

- disabling file count in element [0] (8)

- enabling full path returns (16).

The new parameters are:

- $sCallback - this is the name of a function you want to run on each loop, it is passed an array with data relating to the current file search in the loop. If the callback function returns 0 then the item is processed normally. If it returns 1 the item is skipped (this can be used to skip entire folders being processed). If it returns -1 the entire function errors out with -1 and @extended is set to the callback function's @extended value.

- $sCallbackUserParam - just an extra parameter that can be passed through to the callback function.

Example with callback:

#include <Array.au3>
#include <_FileListToArrayRecursive.au3>

Global $sWFile
_FileListToArrayRecursive(@DesktopDir, '*', 4, '_Callback', 'Wfile')
If @error = -1 And @extended = 42 Then
    MsgBox(0, '', 'You have a W file:' & @LF & $sWFile)
Else
    MsgBox(0, '', 'No files/folders that start with W exist.')
EndIf

Global $aReadOnly = _FileListToArrayRecursive(@DesktopDir, '*', 1+4, '_Callback', 'readonly')
Global $aEmpty = _FileListToArrayRecursive(@DesktopDir, '*', 1+4, '_Callback', 'empty')

_ArrayDisplay($aReadOnly)
_ArrayDisplay($aEmpty)

Func _Callback($aParams)
    Switch $aParams[5]
        Case 'Wfile'
            If StringLeft($aParams[2], 1) == 'W' Then
                $sWFile = $aParams[1] & $aParams[2]
                Return SetExtended(42, -1)
            EndIf
        Case 'empty'
            If Not $aParams[3] Then
                If FileGetSize($aParams[0] & $aParams[1] & $aParams[2]) Then Return 1
            EndIf
        Case 'readonly'
            If Not $aParams[3] Then
                If Not StringInStr(FileGetAttrib($aParams[0] & $aParams[1] & $aParams[2]), 'R') Then Return 1
            EndIf
    EndSwitch
EndFunc

#include-once
; #FUNCTION# ====================================================================================================================
; Name...........: _FileListToArrayRecursive
; Description ...: Lists files and/or folders in a specified path recursively
; Syntax.........: _FileListToArrayRecursive($sPath[, $sFilter = '*'[, $iFlag = 0[, $sCallback = ''[, $sCallbackUserParam = '' ] ] ] ] )
; Parameters ....: $sPath             - Path to search
;                 $sFilter          - Optional: the filter to use, default is *
;                 $iFlag              - Optional: specifies options about return, add flags together
;                 |$iFlag =  0 (Default) Return both files and folders
;                 |$iFlag =  1 Return files only
;                 |$iFlag =  2 Return folders only
;                 |$iFlag =  4 Search subfolders (Enable recursion)
;                 |$iFlag =  8 Make array 0-based (Disable return count in first element)
;                 |$iFlag = 16 Return full paths (default only returns from the search folder down)
;                 $sCallback          - Optional: function to call on each loop. See remarks for details (default: none)
;                 $sCallbackUserParam - Optional: a parameter to pass to the Callback function (default: none)
; Return values .: @Error - 1 = Path not found or invalid
;                 |2 = Invalid $sFilter
;                 |3 = Invalid $iFilter
;                 |4 = No files found or folder inaccessible
;                 |5 = No files found or folder inaccessible
;                 |-1 = Callback function returned -1
; Author ........: Rob Saunders (therks at therks dot com)
; Modified.......:
; Remarks .......: If $sCallback is defined the function will be called on each loop and it can alter what files are recorded
;                 in the return array. The Callback function runs on every file result because it is called *before* the flag
;                 filter for files/folders ($iFlag 1 or 2).
;                   Return  0 = Item is added (depending on $iFlag 1 or 2)
;                   Return  1 = Item is skipped (note: if you skip a folder it will not be searched either)
;                   Return -1 = Stop searching. Main func returns false, @error = -1, @extended = Callback's @extended value
;                 The function is passed one parameter, a 6 item array with values as follows:
;                   [0] root search folder
;                   [1] current sub folder
;                   [2] current filename match
;                   [3] 1 if file is a folder; 0 if not
;                   [4] current file count
;                   [5] $sCallbackUserParam
;
; Related .......: _FileListToArray
; Link ..........:
; Example .......:
; Note ..........: Some parts from original function (by SolidSnake) and _FileListToArrayEx (by DXRW4E)
; ===============================================================================================================================

Func _FileListToArrayRecursive($sPath, $sFilter = '*', $iFlag = 0, $sCallback = '', $sCallbackUserParam = '')
    Local Const $FL_FILES = 1, $FL_FOLDERS = 2, $FL_RECURSE = 4, $FL_NOCOUNT = 8, $FL_FULLPATH = 16

    If Not StringInStr(FileGetAttrib($sPath), 'D') Then Return SetError(1, 1, '')
    If StringRegExp($sFilter, '[\\/:><\|]|(?s)\A\s*\z') Then Return SetError(2, 2, '')
    If $iFlag < 0 Or $iFlag > 1+2+4+8+16 Then Return SetError(3, 3, '')

    $sPath = StringRegExpReplace($sPath, '[\\/]+$', '') & '\'

    Local $sFileTrack, $iFileCount, $hParentSearch, $hSearch, $hSubCheck, $sSubDir, $sFile, $iIsFolder, $sRegExFilter, $sAddFullPath, _
        $iReturnFolders, $iReturnFiles, $iRecurse, $iReturnCount, $iSortOffset, _
        $aCallbackData[6], $vCallbackReturn, $iCallbackExt

    $aCallbackData[5] = $sCallbackUserParam

    If BitAND($iFlag, $FL_FULLPATH) Then $sAddFullPath = $sPath

    If BitAND($iFlag, $FL_RECURSE) Then
        $iRecurse = 1
        If StringReplace($sFilter, '*', '') Then ; If we ARE recursing, and the filter is something besides just * then initialize the regex filter
            $sRegExFilter = '(?i)^' & StringRegExpReplace(StringReplace(StringRegExpReplace($sFilter, '(\.|\||\+|\(|\)|\{|\}|\[|\]|\^|\$|\\)', "\\$1"), '?', '.'), '\*+', '.*') & '$'
            $sFilter = '*'
        EndIf
    EndIf

    If BitAND($iFlag, $FL_FILES) Then
        $iReturnFiles = 1
    ElseIf BitAND($iFlag, $FL_FOLDERS) Then
        $iReturnFolders = 1
    Else
        $iReturnFiles = 1
        $iReturnFolders = 1
    EndIf

    If BitAND($iFlag, $FL_NOCOUNT) Then
        $iReturnCount = 2 ; Param for StringSplit
        $iSortOffset = 0
    EndIf

    $hParentSearch = FileFindFirstFile($sPath & $sSubDir & $sFilter)
    If $hParentSearch = -1 Then Return SetError(4, 4, '')
    $hSearch = $hParentSearch
    While 1
        $sFile = FileFindNextFile($hSearch)
        If @error Then
            If $hParentSearch = $hSearch Then ExitLoop
            FileClose($hSearch)
            $hSearch -= 1
            $sSubDir = StringLeft($sSubDir, StringInStr(StringTrimRight($sSubDir, 1), '\', 0, -1))
            ContinueLoop
        EndIf
        $iIsFolder = @extended

        If $sCallback Then
            $aCallbackData[0] = $sPath
            $aCallbackData[1] = $sSubDir
            $aCallbackData[2] = $sFile
            $aCallbackData[3] = $iIsFolder
            $aCallbackData[4] = $iFileCount
            $vCallbackReturn = Call($sCallback, $aCallbackData)
            If @error = 0xDEAD And @extended = 0xBEEF Then
                FileClose($hSearch)
                FileClose($hParentSearch)
                Return SetError(5, 5, '')
            ElseIf $vCallbackReturn = -1 Then
                $iCallbackExt = @extended
                FileClose($hSearch)
                FileClose($hParentSearch)
                Return SetError(-1, $iCallbackExt, '')
            ElseIf $vCallbackReturn Then
                ContinueLoop
            EndIf
        EndIf

        If $iRecurse Then
            If ($iIsFolder And $iReturnFolders) Or (Not $iIsFolder And $iReturnFiles) Then
                If Not $sRegExFilter Or ($sRegExFilter And StringRegExp($sFile, $sRegExFilter)) Then
                    $sFileTrack &= '|' & $sAddFullPath & $sSubDir & $sFile
                    $iFileCount += 1
                EndIf
            EndIf

            If $iIsFolder Then
                $hSubCheck = FileFindFirstFile($sPath & $sSubDir & $sFile & '\' & $sFilter)
                If $hSubCheck = -1 Then ContinueLoop
                $sSubDir &= $sFile & '\'
                $hSearch = $hSubCheck
            EndIf
        Else
            If ($iIsFolder And $iReturnFolders) Or (Not $iIsFolder And $iReturnFiles) Then
                $sFileTrack &= '|' & $sAddFullPath & $sSubDir & $sFile
                $iFileCount += 1
            EndIf
        EndIf

    WEnd
    FileClose($hParentSearch)

    Local $aReturnList = StringSplit(StringTrimLeft($sFileTrack, 1), '|', $iReturnCount)
    If @error Then Return SetError(4, 4, '')
    Return $aReturnList
EndFunc

I'm still working on this as time goes by so the most up to date version can be found in my dropbox: http://db.tt/OqNgumLK

Edited by therks
Link to post
Share on other sites
  • 4 weeks later...

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
  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By EmilyLove
      I have a string containing the full path of an executable and an array of executables without their paths. I am trying to compare the string to the list in the array and if a match is found, remove it from the array. The entry get removed from the array successfully, and after checking its return result, uses it to update the ubound if it succeeded, but it doesn't want to update to the new value. Any ideas what I am doing wrong? It acts like it is read-only.
      #include <Array.au3> #include <File.au3> Local $sApp_Exe = "F:\App\Nextcloud\nextcloud.exe" Local $aWaitForEXEX = [3, "Nextcloud.exe", "nextcloudcmd.exe", "QtWebEngineProcess.exe"] For $h = 1 To $aWaitForEXEX[0] If StringInStr($sApp_Exe, $aWaitForEXEX[$h]) <> 0 Then $iRet = _ArrayDelete($aWaitForEXEX, $h) If $iRet <> -1 Then $aWaitForEXEX[0] = $iRet ;this line doesn't work. $aWaitForEXEX[0] doesn't update and shortly gives Error: Array variable has incorrect number of subscripts or subscript dimension range exceeded.: _ArrayDisplay($aWaitForEXEX) EndIf Next  
    • By vinnyMS
      #Include <Array.au3> #include <Constants.au3> $s = FileRead("2.txt") Local $w = StringRegExp($s, '(?is)(\b\w+\b)(?!.*\b\1\b)', 3) _ArrayColInsert($w, 1) For $i = 0 to UBound($w)-1 StringRegExpReplace($s, '(?i)\b' & $w[$i][0] & '\b', $w[$i][0]) $w[$i][1] = @extended Next _ArraySort($w, 1, 0, 0, 1) _ArrayDisplay($w) i have this script that returns 3 columns  
       
      i need to copy the  Col 0 and Col 1 as text to paste on notepad or excel
      you will have to create a "copy" button if possible
      array.au3 2.txt
    • By DannyJ
      I have a dataset like this, (a strubg)
      Username: User1 Type: Admin RegDate: 1999 Username: User2 Type: User RegDate: 2000 How to make a 2 dimensional array that I can display with _ArrayDisplay?
      This would be a perfect 2D array to represent my data:
      Username           Tpye RegDate User1              Admin 1999 User2              User 2000   If you run this Powershell this powershell command, you can get this dataset that I am talking about:
      Get-LocalUser | Select * With this code you can try it to read into a string:
      #include <GuiConstantsEx.au3> #include <WindowsConstants.au3> #include "GUIListViewEx.au3" #include <Array.au3> ; Just for display in example #RequireAdmin #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_UseX64=y #EndRegion $sCommand = "powershell.exe Get-LocalUser | Select *" Local $iPid = Run($sCommand, @WorkingDir , @SW_SHOW , $STDOUT_CHILD) ProcessWaitClose($iPid) Local $sOutput = StdoutRead($iPID) ConsoleWrite($sOutput) How can I correctly split $sOutput into a 2D array (with the above mentioned layout) that I can display and I work with?
    • By kovlad
      My solution is to write nested arrays without copying.
      The problem was described hier.
       
      Function:
      #include <Array.au3> ; #FUNCTION# ==================================================================================================================== ; Name ..........: _ArrayNestedSet ; Description ...: Assigns a value to an element of a nested 1D array. ; Syntax ........: _ArrayNestedSet(ByRef $aArray, $vIndex, $vValue) ; Parameters ....: $aArray - an array of arrays. ; $vIndex - an index or 1d-array of indexes; ; a size if $vValue not defined (zero to delete). ; $vValue - a value (create, resize or delete if not defined). ; ; Return values .: on success - 1 ; @extended - nesting level of operation ; on failure - 0 ; @extended - nesting level of error ; @error = 1 - invalid array ; @error = 2 - invalid index ; Author ........: ; Modified ......: kovlad ; Remarks .......: ; Related .......: ; Link ..........: https://www.autoitscript.com/forum/topic/185638-assign-a-value-to-an-array-in-array-element/ ; https://www.autoitscript.com/trac/autoit/ticket/3515?replyto=description ; Example .......: Yes ; =============================================================================================================================== Func _ArrayNestedSet(ByRef $aArray, $vIndex, $vValue = Default) Local $extended = @extended + 1 If IsArray($vIndex) Then If UBound($vIndex, 0) <> 1 Then _ Return SetError(2, $extended) If UBound($vIndex) > 1 Then If UBound($aArray, 0) <> 1 Then _ Return SetError(1, $extended) ; keep index for this array Local $i = $vIndex[0] If $i < 0 Or UBound($aArray) <= $i Then _ Return SetError(2, $extended) ; delete index of this array _ArrayDelete($vIndex, 0) ; recursive function call Local $return = _ArrayNestedSet($aArray[$i], $vIndex, $vValue) If @error Then Return SetError(@error, @extended + 1, 0) Else Return SetExtended(@extended + 1, 1) EndIf Else $vIndex = $vIndex[0] EndIf EndIf If $vValue = Default Then If $vIndex < 0 Then _ Return SetError(2, $extended) If $vIndex = 0 Then ; delete array and free memory $aArray = 0 Return SetExtended($extended, 1) EndIf If UBound($aArray, 0) = 1 Then ; resize array keeping data ReDim $aArray[$vIndex] Return SetExtended($extended, 1) Else ; create new nested array Local $aTmp[$vIndex] $aArray = $aTmp Return SetExtended($extended, 1) EndIf Else If UBound($aArray) <= $vIndex Then _ Return SetError(2, $extended + 1) ; set value of array entry $aArray[$vIndex] = $vValue Return SetExtended($extended, 1) EndIf EndFunc  
      Examples:
      ; write value to 1st nested array ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : write value to 1st nested array" & @CRLF) Local $aTmp1[4] = [1,2,3,4] _ArrayDisplay($aTmp1, "$aTmp1") Local $aArray[2] = [$aTmp1] ConsoleWrite( _ "_ArrayNestedSet($aArray[0], 3, 14) = " & _ArrayNestedSet($aArray[0], 3, 14) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF & @CRLF) _ArrayDisplay($aArray[0], "$aArray[0]") ; resize 1st nested array ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : resize 1st nested array" & @CRLF) ConsoleWrite( _ "_ArrayNestedSet($aArray[0], 8) = " & _ArrayNestedSet($aArray[0], 8) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF & @CRLF) _ArrayDisplay($aArray[0], "$aArray[0]") ; write array to 1st nested array ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : write array to 1st nested array" & @CRLF) Local $aTmp11[4] = [11,12,13,14] _ArrayDisplay($aTmp11, "$aTmp11") ConsoleWrite( _ "_ArrayNestedSet($aArray[0], 2, $aTmp11) = " & _ArrayNestedSet($aArray[0], 2, $aTmp11) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF & @CRLF) _ArrayDisplay(($aArray[0])[2], "($aArray[0])[2]") ; write value to 2nd nested array using index array ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : write value to 2nd nested array using index array" & @CRLF) Local $aIndex1[2] = [2,3] _ArrayDisplay($aIndex1, "$aIndex1") ConsoleWrite( _ "_ArrayNestedSet($aArray[0], $aIndex1, 140) = " & _ArrayNestedSet($aArray[0], $aIndex1, 140) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF & @CRLF) _ArrayDisplay(($aArray[0])[2], "($aArray[0])[2]") ; resize 2nd nested array ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : resize 2nd nested array" & @CRLF) Local $aIndex1[2] = [2,8] _ArrayDisplay($aIndex1, "$aIndex1") ConsoleWrite( _ "_ArrayNestedSet($aArray[0], $aIndex1) = " & _ArrayNestedSet($aArray[0], $aIndex1) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF & @CRLF) _ArrayDisplay(($aArray[0])[2], "($aArray[0])[2]") ; create new 3rd nested array ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : create new 3rd nested array" & @CRLF) Local $aIndex2[3] = [2,7,6] _ArrayDisplay($aIndex2, "$aIndex2") ConsoleWrite( _ "_ArrayNestedSet($aArray[0], $aIndex2) = " & _ArrayNestedSet($aArray[0], $aIndex2) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF & @CRLF) _ArrayDisplay((($aArray[0])[2])[7], ")($aArray[0])[2])[7]") ; delete 3rd nested array ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : delete 3rd nested array" & @CRLF) Local $aIndex3[3] = [2,7,0] _ArrayDisplay($aIndex3, "$aIndex2") ConsoleWrite( _ "_ArrayNestedSet($aArray[0], $aIndex3) = " & _ArrayNestedSet($aArray[0], $aIndex3) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF) ConsoleWrite("IsArray((($aArray[0])[2])[7]) = " & IsArray((($aArray[0])[2])[7]) & @CRLF & @CRLF) ; write 0 in 1st nested array to delete the 2nd nested array ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : write 0 in 1st nested array to delete the 2nd nested array" & @CRLF) Local $aIndex4[1] = [2] _ArrayDisplay($aIndex4, "$aIndex4") ConsoleWrite( _ "_ArrayNestedSet($aArray[0], $aIndex4, 0) = " & _ArrayNestedSet($aArray[0], $aIndex4, 0) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF) ConsoleWrite("IsArray(($aArray[0])[2]) = " & IsArray(($aArray[0])[2]) & @CRLF & @CRLF) ; delete 1st nested array (same as '$aArray[0] = 0') ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : delete 1st nested array (same as '$aArray[0] = 0')" & @CRLF) Local $aIndex5[1] = [0] _ArrayDisplay($aIndex5, "$aIndex5") ConsoleWrite( _ "_ArrayNestedSet($aArray[0], $aIndex5) = " & _ArrayNestedSet($aArray[0], $aIndex5) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF) ConsoleWrite("IsArray($aArray[0]) = " & IsArray($aArray[0]) & @CRLF & @CRLF)  
    • By DannyJ
      $sCommands1 = 'powershell.exe Get-ChildItem' $iPid = run($sCommands1   , @WorkingDir , @SW_SHOW , 0x2) $sOutput = ""  While 1     $sOutput &= StdoutRead($iPID)         If @error Then             ExitLoop         EndIf  WEnd ;~ msgbox(0, '' , $sOutput) ConsoleWrite("$sOutput") ConsoleWrite($sOutput) ConsoleWrite(@CRLF) $aOutput = stringsplit($sOutput ,@LF , 2) For $i=0 To  UBound($aOutput) - 1 Step 1     ConsoleWrite($aOutput[$i]) Next The script above reads the whole directory into a one dimensional array, but I need to work with the array, so I need to split the array into multiple dimensions.
      I have already read some forum answers here, and I have already tried these commands:
       
      Are there any way to use the $aOutput variable like in PowerShell:
      PowerShell:
      $a = Get-ChildItem $a.Mode I imagine this in AutoIt  $aOutput
      ConsoleWrite($aOutput[i].Mode) Or if I split this command into 2 dimension like:
      For $i To UBound($aOutput)-1 Step 1 ConsoleWrite($aOutput[$i][1]) ConsoleWrite($aOutput[$i][2]) Next  
×
×
  • Create New...