Jump to content

Improvement of included _FileListToArray function.


Tlem
 Share

Recommended Posts

  • Moderators

Hi Danny35, you'll run into a recursion issue on very (very very) large directories (4810 I believe).

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

  • Replies 265
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

I only added the "For $y = 1 to 10/next" loop to give more of an average time of function calls, compensate for disk caching, etc. The NT version still holds up pretty well against the Ex.

But there have been tons of BugTrac requests over time, and tons of threads regarding enhancing _FileListToArray either functionally, or performance-wise. There's a thread or two right now running concurrent to this one that are on the same topic. I think that indicates that A: Everyone thinks that FIleListToArray needs a makeover, and B: Most everyone has their own idea how to go about it. Alternative methods, ideas, suggestions are all great for producing the best product possible. One that might cut the number of BugTrac enhancement requests, and forum discussions down to a minimum for a long time to come.

I almost wonder if once we think we've reached the best result we can, one that is polished and tested, that we ought to open up one last (new) forum thread titled something like "Open Discussion: New _FileListToArray() proposal" then subtitle it "Beat it, break it, or make it better!". The purpose would be to suck in those participating in other similar threads to get them involved and ensure there is not something better floating around out there. I'm rambling... pardon.

CODE
#include <File.au3>
#include <Date.au3>
#include <Array.au3>

$Path = "C:\Program Files\Autoit3"

For $x = 0 To 2
    CalcTime('Start')
    For $y = 1 to 10
        $aFiles = _FileListToArrayNT($Path, '*', $x, 2, 1, '', 0)
    Next
    $error = @error
    $Time1 = Int(CalcTime('Finish'))
    If IsArray($aFiles) Then
        ConsoleWrite('Files/Folders ' & UBound($aFiles) & ' Improve Flag = ' & $x & ' Time: ' & $Time1 & @CRLF)
;_ArrayDisplay($aFiles, 'Improve Flag = ' & $x & ' Time: ' & $Time1)
        _ArraySort($aFiles, 0)
    Else
        ConsoleWrite('Improve Error: ' & $error & ' Flag = ' & $x & ' Time: ' & $Time1 & '  ' & @CRLF)
    EndIf

    CalcTime('Start')
                ;($sPath, $sFilter = '*', $iFlag = 0, $iPathType = 1, $iRecursive = 0, $sExclude = "", $iRetFormat = 0)
    For $y = 1 to 10
        $aFiles = _FileListToArrayEx($Path, '*', $x, 1, 1, '', 2)
    Next
    $error = @error
    $Time2 = Int(CalcTime('Finish'))
    If IsArray($aFiles) Then
        ConsoleWrite('Files/Folders ' & UBound($aFiles) & ' Danny35D Flag = ' & $x & ' Time: ' & $Time2 & @CRLF)
;_ArrayDisplay($aFiles, 'Danny35D Flag = ' & $x & ' Time: ' & $Time2)
        _ArraySort($aFiles)
    Else
        ConsoleWrite('Dan Error: ' & $error & ' Flag = ' & $x & ' Time: ' & $Time2 & @CRLF)
    EndIf
    If $Time1 < $Time2 Then
        $Percent = Round(100 - ($Time1/$Time2) * 100, 2)
        ConsoleWrite('Faster: Improve ' & $Percent & '%' & @CRLF & @CRLF)
    Else
        $Percent = Round(100 - ($Time2/$Time1) * 100, 2)
        ConsoleWrite('Faster Danny35d ' & $Percent & '%' & @CRLF & @CRLF)
    EndIf
Next

Func CalcTime($Action, $iMsgBox = 0)
    Local $CalcTimestamp_2[2], $Msecs, $Secs, $Mins, $Hour
    If $Action = "Start" Then
        Global $CalcTimestamp_1[2]
        $CalcTimestamp_1[0] = TimerInit()
    ElseIf $Action = "Finish" Then
        $CalcTimestamp_2[1] = TimerDiff($CalcTimestamp_1[0])
    EndIf
    Return ($CalcTimestamp_2[1])
EndFunc;==>CalcTime

;===============================================================================
Func _FileListToArrayEx($sPath, $sFilter = '*', $iFlag = 0, $iPathType = 1, $iRecursive = 0, $sExclude = "", $iRetFormat = 0, $iRunFirstTime = 1)
    Local $aFileList = '', $aFolderList = '', $Tmp = '', $sMask

    If $iRunFirstTime Then
        $sPath = StringRegExpReplace($sPath, '\\+$', ''); Removed trailing backslash
        If Not FileExists($sPath) Then Return SetError(1, 1, 'Path Not Found Or Invalid.')
        If StringRegExp($sFilter, '[\\/:><\|]') Then Return SetError(2, 2, 'Invalid Mask('& $sFilter & ').')
        If Not StringRegExp($iFlag, '[012]') Then Return SetError(3, 3, 'Invalid Flag, Chooce (0,1 or 2).')
        If Not StringRegExp($iPathType, '[01]') Then Return SetError(5, 5, 'Invalid Path Type, Choose (0 or 1).')
        If Not StringRegExp($iRecursive, '[01]') Then Return SetError(6, 6, 'Invalid Recursive, Choose (0 or 1).')
        If Not StringRegExp($iRetFormat, '[012]') Then Return SetError(7, 7, 'Invalid RetFormat, Choose (0, 1 or 2).')
    EndIf

    $sMask = '(?i)^' & StringReplace(StringReplace(StringReplace($sFilter, '.', '\.'), '*', '.*'), '?', '.')
    If $sExclude <> '' And $iRunFirstTime Then;convert $sExclude to fit StringRegExp (not perfect but useable)
        $sExclude = StringStripWS(StringRegExpReplace($sExclude, "\s*;\s*", ";"), 3);Strip leading and trailing spaces and spaces between semi colon delimiter
        $sExclude = StringRegExpReplace($sExclude, '([\Q\.+[^]$(){}=!\E])', '\\$1');thanks KaFu and Ascend4nt
        $sExclude = "(?i)\A" & StringReplace(StringReplace(StringReplace($sExclude, "?", "."), "*", ".*?"), ";", "|") & "\z"
    EndIf

    $iFirstFile = FileFindFirstFile($sPath & '\*')
    If @error Then Return
    While True
        $iNextFile = FileFindNextFile($iFirstFile)
        If @error Then ExitLoop
        $extended = @extended
        $sFullPath = $sPath & '\' & $iNextFile
        If $extended = 1 Then
            If $iFlag <> 1 And ($sFilter = '*' Or $sFilter = '*.*') Then $aFileList &= $sFullPath & '|'
            If $iRecursive Then
                If $sExclude <> '' And StringRegExp(StringRegExpReplace($sFullPath, "(.*?[\\/]+)*(.*?\z)", "\2"), $sExclude) Then ContinueLoop
                $Tmp = _FileListToArrayEx($sFullPath, $sFilter, $iFlag, $iPathType, $iRecursive, $sExclude, 1, 0)
                If $Tmp <> Chr(38) And $Tmp <> ChrW(38) Then $aFileList &= $Tmp
            EndIf
        Else
            If Not StringRegExp($iNextFile, $sMask) Then ContinueLoop
            If Not StringRegExp(StringRegExpReplace($sFilter, '^.*\.', ''), '[?*]') Then
                If StringRegExpReplace($sFilter, '^.*\.', '') <> StringRegExpReplace($iNextFile, '^.*\.', '') Then ContinueLoop
            EndIf
            If $sExclude <> '' And StringRegExp(StringRegExpReplace($sFullPath, "(.*?[\\/]+)*(.*?\z)", "\2"), $sExclude) Then ContinueLoop
            If $iFlag <> 2 Then $aFileList &= $sFullPath & '|'
        EndIf
    WEnd
    FileClose($iFirstFile)

    If $iRunFirstTime Then
        $aFileList = StringTrimRight($aFileList, 1)
        If StringLen($aFileList) = 0 Then Return SetError(4, 4, 'No File(s) Found.')
        If $iPathType = 0 Then $aFileList = StringReplace($aFileList, $sPath & '', '')
        If $iRetFormat <> 1 Then $aFileList = StringSplit($aFileList, '|', $iRetFormat)
    EndIf
    Return ($aFileList)
EndFunc;==>_FileListToArrayEx

;===============================================================================
Func _FileListToArrayNT($sPath = @ScriptDir, $sFilter = "*", $iSearchType = 0, $iPathType = 0, $bRecursiv = False, $sExclude = "", $iRetFormat = 1, $sWorkPath = "")
  Local $hSearch, $iPCount, $iFCount, $sFile, $sFileList, $sTExclude, $sTWorkPath

  If $sPath = -1 Or $sPath = Default Then $sPath = @ScriptDir
  If $sFilter = -1 Or $sFilter = Default Then $sFilter = "*"
  If $iSearchType = -1 Or $iSearchType = Default Then $iSearchType = 0
  If $iPathType = -1 Or $iPathType = Default Then $iPathType = 0
  If $bRecursiv = Default Then $bRecursiv = False
  If $sExclude = -1 Or $sExclude = Default Then $sExclude = ""
  If $iRetFormat = -1 Or $iRetFormat = Default Then $iRetFormat = 1

  Local $aPath = StringSplit($sPath, ';');paths array
  Local $aFilter = StringSplit($sFilter, ';');filters array

  If $sExclude Then

;prepare $sTExclude
;strip leading and trailing spaces and spaces between semi colon delimiter
    $sTExclude = StringStripWS(StringRegExpReplace($sExclude, "\s*;\s*", ";"), 3)
;convert $sExclude to fit StringRegExp (not perfect but useable)
    $sTExclude = StringRegExpReplace($sTExclude, '([\Q\.+[^]$(){}=!\E])', '\\$1');thanks KaFu and Ascend4nt
    $sTExclude = StringReplace($sTExclude, "?", ".")
    $sTExclude = StringReplace($sTExclude, "*", ".*?")
    $sTExclude = "(?i)\A" & StringReplace($sTExclude, ";", "|") & "\z"

    For $iPCount = 1 To $aPath[0];Path loop
      Local $sPathItem = StringStripWS($aPath[$iPCount], 3);strip leading and trailing spaces
      Local $sDelim = "|";reset $sDelim

      If StringRight($sPathItem, 1) <> "\" Then $sPathItem &= "\";ensure trailing slash

      If $iPathType = 2 Then $sDelim &= $sPathItem;return full-path

      For $iFCount = 1 To $aFilter[0];Filter loop
        Local $FilterItem = StringStripWS($aFilter[$iFCount], 3);strip leading and trailing spaces
        If StringRegExp($FilterItem, "[\\/:<>|]") Then ContinueLoop;bypass filters with invalid chars
        $hSearch = FileFindFirstFile($sPathItem & $FilterItem)
        If @error Then ContinueLoop
        Switch $iSearchType
          Case 1;files Only
            While True
              $sFile = FileFindNextFile($hSearch)
              If @error Then ExitLoop
              If @extended Then ContinueLoop;bypass folder
;check for exclude files
              If StringRegExp(StringRegExpReplace($sFile, "(.*?[\\/]+)*(.*?\z)", "\2"), $sTExclude) Then ContinueLoop
              $sFileList &= $sDelim & $sWorkPath & $sFile
            WEnd
          Case 2;folders Only
            While True
              $sFile = FileFindNextFile($hSearch)
              If @error Then ExitLoop
              If @extended = 0 Then ContinueLoop;bypass file
;check for exclude folder
              If StringRegExp(StringRegExpReplace($sFile, "(.*?[\\/]+)*(.*?\z)", "\2"), $sTExclude) Then ContinueLoop
              $sFileList &= $sDelim & $sWorkPath & $sFile
            WEnd
          Case Else;files and folders
            While True
              $sFile = FileFindNextFile($hSearch)
              If @error Then ExitLoop
;check for exclude files/folder
              If StringRegExp(StringRegExpReplace($sFile, "(.*?[\\/]+)*(.*?\z)", "\2"), $sTExclude) Then ContinueLoop
              $sFileList &= $sDelim & $sWorkPath & $sFile
            WEnd
        EndSwitch
        FileClose($hSearch)
      Next;$iFCount - next filter

;---------------

;optional do a recursive search
      If $bRecursiv Then
        $hSearch = FileFindFirstFile($sPathItem & "*.*")
        If Not @error Then
          While True
            $sFile = FileFindNextFile($hSearch)
            If @error Then ExitLoop
            If @extended = 0 Then ContinueLoop;bypass file (for Autoit versions > 3.3.0.0)
;check for exclude folder
            If StringRegExp(StringRegExpReplace($sFile, "(.*?[\\/]+)*(.*?\z)", "\2"), $sTExclude) Then ContinueLoop
;call recursive search
            If $iPathType = 1 Then $sTWorkPath = $sWorkPath & $sFile & "\"
            $sFileList &= _FileListToArrayNT($sPathItem & $sFile & "\", $sFilter, $iSearchType, $iPathType, $bRecursiv, $sExclude, 2, $sTWorkPath)
          WEnd
          FileClose($hSearch)
        EndIf
      EndIf

    Next;$iPCount - next path

  Else;If Not $sExclude

    For $iPCount = 1 To $aPath[0];path loop
      Local $sPathItem = StringStripWS($aPath[$iPCount], 3);strip leading and trailing spaces
      Local $sDelim = "|";reset $sDelim

      If StringRight($sPathItem, 1) <> "\" Then $sPathItem &= "\";ensure trailing slash

;return full-path
      If $iPathType = 2 Then $sDelim &= $sPathItem

;perform the search
      For $iFCount = 1 To $aFilter[0];Filter loop
        Local $FilterItem = StringStripWS($aFilter[$iFCount], 3);strip leading and trailing spaces
        If StringRegExp($FilterItem, "[\\/:<>|]") Then ContinueLoop;bypass filters with invalid chars
        $hSearch = FileFindFirstFile($sPathItem & $FilterItem)
        If @error Then ContinueLoop
        Switch $iSearchType
          Case 1;files Only
            While True
              $sFile = FileFindNextFile($hSearch)
              If @error Then ExitLoop
              If @extended Then ContinueLoop;bypass folder
              $sFileList &= $sDelim & $sWorkPath & $sFile
            WEnd
          Case 2;folders Only
            While True
              $sFile = FileFindNextFile($hSearch)
              If @error Then ExitLoop
              If @extended = 0 Then ContinueLoop;bypass file
              $sFileList &= $sDelim & $sWorkPath & $sFile
            WEnd
          Case Else;files and folders
            While True
              $sFile = FileFindNextFile($hSearch)
              If @error Then ExitLoop
              $sFileList &= $sDelim & $sWorkPath & $sFile
            WEnd
        EndSwitch
        FileClose($hSearch)
      Next;$iFCount - next filter

;---------------

;optional do a recursive search
      If $bRecursiv Then
        $hSearch = FileFindFirstFile($sPathItem & "*.*")
        If Not @error Then
          While True
            $sFile = FileFindNextFile($hSearch)
            If @error Then ExitLoop
            If @extended = 0 Then ContinueLoop;bypass file (for Autoit versions > 3.3.0.0)
;call recursive search
            If $iPathType = 1 Then $sTWorkPath = $sWorkPath & $sFile & "\"
            $sFileList &= _FileListToArrayNT($sPathItem & $sFile & "\", $sFilter, $iSearchType, $iPathType, $bRecursiv, $sExclude, 2, $sTWorkPath)
          WEnd
          FileClose($hSearch)
        EndIf
      EndIf

    Next;$iPCount - next path

  EndIf;If $sExclude

;---------------

;set according return value
  If $sFileList Then
    Switch $iRetFormat
      Case 2;return a delimited string
        Return $sFileList
      Case 0;return a 0-based array
        Return StringSplit(StringTrimLeft($sFileList, 1), "|", 2)
      Case Else;return a 1-based array
        Return StringSplit(StringTrimLeft($sFileList, 1), "|", 1)
    EndSwitch
  Else
    Return SetError(4, 4, "")
  EndIf

EndFunc;==>_FileListToArrayNT

Edit: Ahem "B" and ")" makes a smiley face, ruined the effect of my listing off reasons outline-style. I'll try A: and B: instead.

Edit2:Removed writes to H: drive logfile

Edited by Spiff59
Link to comment
Share on other sites

I chopped up the NT version (or FileListToArrayTurbo3000Plus, as I like to call it).

The test below is set to run it a single time, files-and-folders, recursion on, and forced into exclude mode.

My question is about the StringRegExpReplace used a number of times to exclude files.

What the heck does it do???

I ran this test on my entire C: RAID array and my backup D: drive, 220,000+ files. Not once did either of the Msgbox() statements I plugged in there pop up.

To repeat, what is the function of that SRER that we have in 4 places on the exclude side of the script???

It never kicks in once on either of my drives.

CODE
$Path = "C:"
$aFiles = _FileListToArrayNT($Path, '*', 0, 2, True, '*.ini', 1)
MsgBox(1,"",$aFiles[0])
Exit

;===============================================================================
Func _FileListToArrayNT($sPath = @ScriptDir, $sFilter = "*", $iSearchType = 0, $iPathType = 0, $bRecursiv = False, $sExclude = "", $iRetFormat = 1, $sWorkPath = "")
  Local $hSearch, $iPCount, $iFCount, $sFile, $sFileList, $sTExclude, $sTWorkPath

  If $sPath = -1 Or $sPath = Default Then $sPath = @ScriptDir
  If $sFilter = -1 Or $sFilter = Default Then $sFilter = "*"
  If $iSearchType = -1 Or $iSearchType = Default Then $iSearchType = 0
  If $iPathType = -1 Or $iPathType = Default Then $iPathType = 0
  If $bRecursiv = Default Then $bRecursiv = False
  If $sExclude = -1 Or $sExclude = Default Then $sExclude = ""
  If $iRetFormat = -1 Or $iRetFormat = Default Then $iRetFormat = 1

  Local $aPath = StringSplit($sPath, ';');paths array
  Local $aFilter = StringSplit($sFilter, ';');filters array

;prepare $sTExclude
;strip leading and trailing spaces and spaces between semi colon delimiter
    $sTExclude = StringStripWS(StringRegExpReplace($sExclude, "\s*;\s*", ";"), 3)
;convert $sExclude to fit StringRegExp (not perfect but useable)
    $sTExclude = StringRegExpReplace($sTExclude, '([\Q\.+[^]$(){}=!\E])', '\\$1');thanks KaFu and Ascend4nt
    $sTExclude = StringReplace($sTExclude, "?", ".")
    $sTExclude = StringReplace($sTExclude, "*", ".*?")
    $sTExclude = "(?i)\A" & StringReplace($sTExclude, ";", "|") & "\z"

    For $iPCount = 1 To $aPath[0];Path loop
      Local $sPathItem = StringStripWS($aPath[$iPCount], 3);strip leading and trailing spaces
      Local $sDelim = "|";reset $sDelim

      If StringRight($sPathItem, 1) <> "\" Then $sPathItem &= "\";ensure trailing slash

      If $iPathType = 2 Then $sDelim &= $sPathItem;return full-path

      For $iFCount = 1 To $aFilter[0];Filter loop
        Local $FilterItem = StringStripWS($aFilter[$iFCount], 3);strip leading and trailing spaces
        If StringRegExp($FilterItem, "[\\/:<>|]") Then ContinueLoop;bypass filters with invalid chars
        $hSearch = FileFindFirstFile($sPathItem & $FilterItem)
        If @error Then ContinueLoop
            While True
              $sFile = FileFindNextFile($hSearch)
              If @error Then ExitLoop
;check for exclude files/folder
              $x = StringRegExpReplace($sFile, "(.*?[\\/]+)*(.*?\z)", "\2")
              If $sFile <> $x Then MsgBox(1,"",$sfile & @CRLF & $x)
              If StringRegExp($x, $sTExclude) Then ContinueLoop
              $sFileList &= $sDelim & $sWorkPath & $sFile
            WEnd
        FileClose($hSearch)
      Next;$iFCount - next filter

;---------------

;optional do a recursive search
      If $bRecursiv Then
        $hSearch = FileFindFirstFile($sPathItem & "*.*")
        If Not @error Then
          While True
            $sFile = FileFindNextFile($hSearch)
            If @error Then ExitLoop
            If @extended = 0 Then ContinueLoop;bypass file (for Autoit versions > 3.3.0.0)
;check for exclude folder
              $x = StringRegExpReplace($sFile, "(.*?[\\/]+)*(.*?\z)", "\2")
              If $sFile <> $x Then MsgBox(1,"",$sfile & @CRLF & $x)
            If StringRegExp($x, $sTExclude) Then ContinueLoop
;call recursive search
            If $iPathType = 1 Then $sTWorkPath = $sWorkPath & $sFile & "\"
            $sFileList &= _FileListToArrayNT($sPathItem & $sFile & "\", $sFilter, $iSearchType, $iPathType, $bRecursiv, $sExclude, 2, $sTWorkPath)
          WEnd
          FileClose($hSearch)
        EndIf
      EndIf

    Next;$iPCount - next path

;---------------

;set according return value
  If $sFileList Then
    Switch $iRetFormat
      Case 2;return a delimited string
        Return $sFileList
      Case 0;return a 0-based array
        Return StringSplit(StringTrimLeft($sFileList, 1), "|", 2)
      Case Else;return a 1-based array
        Return StringSplit(StringTrimLeft($sFileList, 1), "|", 1)
    EndSwitch
  Else
    Return SetError(4, 4, "")
  EndIf

EndFunc;==>_FileListToArrayNT

Edit: It appears it's trying to do something with forward and backward slashes that occur at the end of the string?

Edit2: If the string contains a forward or backward slash, it returns only the portion of the string to the right of the last slash. Does FileFindNextFile ever return a string containing a slash??? I"m thinkng we can give the exclude side of the function a speed boost by throwing out all four of those SRER's and making the lines just:

If StringRegExp($x, $sTExclude) Then ContinueLoop

?

Edited by Spiff59
Link to comment
Share on other sites

Thanks!, that is what it didn't make sence to me. How come a script that is over 100 line longer can process faster?

Thats very easy: you have less If...Then decisions cause you have made the decision once (ex: the exclude decision),

so the decision-tree (i hope that are the right words) is shorter.

(sometimes detours are faster)

I have tested your last code:

(one path with 10584 files, 1560 folders, filter="*", return files/folders, full path, recursion, with one exclusion (folder exclusion)

The speed is almost fast as _FileListToArrayNT but the result is a little bit wrong

_FileListToArrayNT: Sec = 35.94 , 9719 items

_FileListToArrayDanny: Sec = 36.08 , 9720 items

Your code returns the name of the excluded folder.

(No criticism, just comment) ;-) :-)

But i have seen a good idea in your code, the $iRunFirstTime flag for parameter checking.

I will try to implement it in _FileListToArrayNT.

(the drawback is, there will be another unused parameter in function, maybe i find a solution for that)

So you have made a good suggestion.

Edited by BaKaMu
Link to comment
Share on other sites

I chopped up the NT version (or FileListToArrayTurbo3000Plus, as I like to call it).

My Tests:

(one path with 10584 files, 1560 folders, filter="*", return files/folders, full path, recursion, with no exclusion

_FileListToArrayNT: Sec = 17.27 , 12144 items

FileListToArrayTurbo3000Plus: Sec = 27.64 , 12144 items

(one path with 10584 files, 1560 folders, filter="*", return files/folders, full path, recursion, with one exclusion (folder exclusion)

_FileListToArrayNT: Sec = 21.58 , 9719 items

FileListToArrayTurbo3000Plus: Sec = 22.38 , 9719 items

So there isn't really a speed improvement. ;-(

But i have seen a good suggestion in the code of Danny35d ($iRunFirstTime flag).

I will give it a try (in case of free time)

Edit2: If the string contains a forward or backward slash, it returns only the portion of the string to the right of the last slash. Does FileFindNextFile ever return a string containing a slash??? I"m thinkng we can give the exclude side of the function a speed boost by throwing out all four of those SRER's and making the lines just:

If StringRegExp($x, $sTExclude) Then ContinueLoop?

I will think about that.
Link to comment
Share on other sites

Link to comment
Share on other sites

But i have seen a good suggestion in the code of Danny35d ($iRunFirstTime flag).

I will give it a try (in case of free time)

Now i have implemented the suggestion of Danny35d (thanks for this advise)

and to my surprise there is a significant speed improvement

because now the parameter checking will be done only once in recursion:

(It is even faster then my private _FileListToArrayOpt Version)

Test1: (one path with 10584 files, 1560 folders, filter="*", return files/folders, full path, recursion, with no exclusion, repeat 30 times

_FileListToArrayNT: Sec = 17.33 , 12144 items

_FileListToArrayNT3: Sec = 16.22 , 12144 items

Test2: (one path with 10584 files, 1560 folders, filter="*", return files/folders, full path, recursion, with one exclusion (folder exclusion), repeat 30 times

_FileListToArrayNT: Sec = 21.52 , 9719 items

_FileListToArrayNT3: Sec = 19.59 , 9719 items

So this is again a step forward.

The only drawback is the second "do not use" parameter $iRunFirstTime (but that maybe the cost of the advantage in speed)

_FileListToArrayNT3 (or FileListToArrayUltra4000Plus, as Spiff59 would like to call it) :-)

; #FUNCTION# ===========================================================================================
; Name:             _FileListToArrayNT3
; Description:      full compatible _FileListToArray replacement  (with greater performance and additional features)
;                   additional: multi-path, multi-filter, multi-exclude-filter, path format options, recursive search
; Syntax:           _FileListToArrayNT3([$sPath = @ScriptDir, [$sFilter = "*", [$iSearchType, [$bRecursiv = False, [$sExclude = "", [$iRetFormat = 1]]]]]])
; Parameter(s):     $sPath = optional: Search path(s), semicolon delimited (default: @ScriptDir)
;                             (Example: "C:\Tmp;D:\Temp")
;                   $sFilter = optional: Search filter(s), semicolon delimited . Wildcards allowed. (default: "*")
;                              (Example: "*.exe;*.txt")
;                   $iSearchType = Include in search: 0 = Files and Folder, 1 = Files Only, 2 = Folders Only
;                   $iPathType = Returned element format: 0 = file/folder name only, 1 = relative path, 2 = full path
;                   $bRecursiv = optional: True: recursive search including all subdirectories
;                                          False (default): search only in specified folder
;                   $sExclude = optional: Exclude filter(s), semicolon delimited. Wildcards allowed.
;                                (Example: "Unins*" will remove all files/folders that begin with "Unins")
;                   $iRetFormat =  optional: return format
;                                  0 = one-dimensional array, 0-based
;                                  1 = one-dimensional array, 1-based (default)
;                                  2 = String ( "|" delimited)
;                   $sWorkPath =     *** internal use only (do not use) ***
;                   $iRunFirstTime = *** internal use only (do not use) ***
; Requirement(s):   none
; Return Value(s):  on success: 1-based or 0-based array or string (dependent on $iRetFormat)
;                   If no data is found, @error is set (to 4, for backwards compatibility)
; Author(s):        Half the AutoIt Community
; ====================================================================================================
Func _FileListToArrayNT3($sPath = @ScriptDir, $sFilter = "*", $iSearchType = 0, $iPathType = 0, $bRecursiv = False, $sExclude = "", $iRetFormat = 1, $sWorkPath = "", $iRunFirstTime = True)
  Local $hSearch, $iPCount, $iFCount, $sFile, $sFileList, $sTWorkPath

  If $iRunFirstTime Then
    If $sPath = -1 Or $sPath = Default Then $sPath = @ScriptDir
    If $sFilter = -1 Or $sFilter = Default Then $sFilter = "*"
    If $iSearchType = -1 Or $iSearchType = Default Then $iSearchType = 0
    If $iPathType = -1 Or $iPathType = Default Then $iPathType = 0
    If $bRecursiv = Default Then $bRecursiv = False
    If $sExclude = -1 Or $sExclude = Default Then $sExclude = ""
    If $iRetFormat = -1 Or $iRetFormat = Default Then $iRetFormat = 1

    If $sExclude Then
      ;prepare $sExclude
      ;strip leading and trailing spaces and spaces between semi colon delimiter
      $sExclude = StringStripWS(StringRegExpReplace($sExclude, "\s*;\s*", ";"), 3)
      ;convert $sExclude to fit StringRegExp (not perfect but useable)
      $sExclude = StringRegExpReplace($sExclude, '([\Q\.+[^]$(){}=!\E])', '\\$1') ;thanks KaFu and Ascend4nt
      $sExclude = StringReplace($sExclude, "?", ".")
      $sExclude = StringReplace($sExclude, "*", ".*?")
      $sExclude = "(?i)\A" & StringReplace($sExclude, ";", "|") & "\z"
    EndIf

    ;strip leading and trailing spaces and spaces between semi colon delimiter
    $sPath = StringStripWS(StringRegExpReplace($sPath, "\s*;\s*", ";"), 3)
    $sFilter = StringStripWS(StringRegExpReplace($sFilter, "\s*;\s*", ";"), 3)

    $iRunFirstTime = False
  EndIf

  Local $aPath = StringSplit($sPath, ';') ;paths array
  Local $aFilter = StringSplit($sFilter, ';') ;filters array

  If $sExclude Then

    For $iPCount = 1 To $aPath[0] ;Path loop
      Local $sDelim = "|" ;reset $sDelim

      If StringRight($aPath[$iPCount], 1) <> "\" Then $aPath[$iPCount] &= "\" ;ensure trailing slash

      If $iPathType = 2 Then $sDelim &= $aPath[$iPCount] ;return full-path

      For $iFCount = 1 To $aFilter[0] ;Filter loop
        If StringRegExp($aFilter[$iFCount], "[\\/:<>|]") Then ContinueLoop ;bypass filters with invalid chars
        $hSearch = FileFindFirstFile($aPath[$iPCount] & $aFilter[$iFCount])
        If @error Then ContinueLoop
        Switch $iSearchType
          Case 1 ;files Only
            While True
              $sFile = FileFindNextFile($hSearch)
              If @error Then ExitLoop
              If @extended Then ContinueLoop ;bypass folder
              ;check for exclude files
              If StringRegExp(StringRegExpReplace($sFile, "(.*?[\\/]+)*(.*?\z)", "\2"), $sExclude) Then ContinueLoop
              $sFileList &= $sDelim & $sWorkPath & $sFile
            WEnd
          Case 2 ;folders Only
            While True
              $sFile = FileFindNextFile($hSearch)
              If @error Then ExitLoop
              If @extended = 0 Then ContinueLoop ;bypass file
              ;check for exclude folder
              If StringRegExp(StringRegExpReplace($sFile, "(.*?[\\/]+)*(.*?\z)", "\2"), $sExclude) Then ContinueLoop
              $sFileList &= $sDelim & $sWorkPath & $sFile
            WEnd
          Case Else ;files and folders
            While True
              $sFile = FileFindNextFile($hSearch)
              If @error Then ExitLoop
              ;check for exclude files/folder
              If StringRegExp(StringRegExpReplace($sFile, "(.*?[\\/]+)*(.*?\z)", "\2"), $sExclude) Then ContinueLoop
              $sFileList &= $sDelim & $sWorkPath & $sFile
            WEnd
        EndSwitch
        FileClose($hSearch)
      Next ;$iFCount - next filter

      ;---------------

      ;optional do a recursive search
      If $bRecursiv Then
        $hSearch = FileFindFirstFile($aPath[$iPCount] & "*.*")
        If Not @error Then
          While True
            $sFile = FileFindNextFile($hSearch)
            If @error Then ExitLoop
            If @extended = 0 Then ContinueLoop ;bypass file (for Autoit versions > 3.3.0.0)
            ;check for exclude folder
            If StringRegExp(StringRegExpReplace($sFile, "(.*?[\\/]+)*(.*?\z)", "\2"), $sExclude) Then ContinueLoop
            ;call recursive search
            If $iPathType = 1 Then $sTWorkPath = $sWorkPath & $sFile & "\"
            $sFileList &= _FileListToArrayNT3($aPath[$iPCount] & $sFile & "\", $sFilter, $iSearchType, $iPathType, $bRecursiv, $sExclude, 2, $sTWorkPath, $iRunFirstTime)
          WEnd
          FileClose($hSearch)
        EndIf
      EndIf

    Next ;$iPCount - next path

  Else ;If Not $sExclude

    For $iPCount = 1 To $aPath[0] ;path loop
      Local $sDelim = "|" ;reset $sDelim

      If StringRight($aPath[$iPCount], 1) <> "\" Then $aPath[$iPCount] &= "\" ;ensure trailing slash

      ;return full-path
      If $iPathType = 2 Then $sDelim &= $aPath[$iPCount]

      ;perform the search
      For $iFCount = 1 To $aFilter[0] ;Filter loop
        If StringRegExp($aFilter[$iFCount], "[\\/:<>|]") Then ContinueLoop ;bypass filters with invalid chars
        $hSearch = FileFindFirstFile($aPath[$iPCount] & $aFilter[$iFCount])
        If @error Then ContinueLoop
        Switch $iSearchType
          Case 1 ;files Only
            While True
              $sFile = FileFindNextFile($hSearch)
              If @error Then ExitLoop
              If @extended Then ContinueLoop ;bypass folder
              $sFileList &= $sDelim & $sWorkPath & $sFile
            WEnd
          Case 2 ;folders Only
            While True
              $sFile = FileFindNextFile($hSearch)
              If @error Then ExitLoop
              If @extended = 0 Then ContinueLoop ;bypass file
              $sFileList &= $sDelim & $sWorkPath & $sFile
            WEnd
          Case Else ;files and folders
            While True
              $sFile = FileFindNextFile($hSearch)
              If @error Then ExitLoop
              $sFileList &= $sDelim & $sWorkPath & $sFile
            WEnd
        EndSwitch
        FileClose($hSearch)
      Next ;$iFCount - next filter

      ;---------------

      ;optional do a recursive search
      If $bRecursiv Then
        $hSearch = FileFindFirstFile($aPath[$iPCount] & "*.*")
        If Not @error Then
          While True
            $sFile = FileFindNextFile($hSearch)
            If @error Then ExitLoop
            If @extended = 0 Then ContinueLoop ;bypass file (for Autoit versions > 3.3.0.0)
            ;call recursive search
            If $iPathType = 1 Then $sTWorkPath = $sWorkPath & $sFile & "\"
            $sFileList &= _FileListToArrayNT3($aPath[$iPCount] & $sFile & "\", $sFilter, $iSearchType, $iPathType, $bRecursiv, $sExclude, 2, $sTWorkPath, $iRunFirstTime)
          WEnd
          FileClose($hSearch)
        EndIf
      EndIf

    Next ;$iPCount - next path

  EndIf ;If $sExclude

  ;---------------

  ;set according return value
  If $sFileList Then
    Switch $iRetFormat
      Case 2 ;return a delimited string
        Return $sFileList
      Case 0 ;return a 0-based array
        Return StringSplit(StringTrimLeft($sFileList, 1), "|", 2)
      Case Else ;return a 1-based array
        Return StringSplit(StringTrimLeft($sFileList, 1), "|", 1)
    EndSwitch
  Else
    Return SetError(4, 4, "")
  EndIf

EndFunc   ;==>_FileListToArrayNT3
Edited by BaKaMu
Link to comment
Share on other sites

  • Moderators

SmOke_N, I guess that's more a theoretical then a practical issue (5100).

#699650

To be honest my curiosity got the better of me. I couldn't even create a 5000 deep sub directory (well I could, but they wouldn't open). Seems to be a 250 or so limit on them... so recursion would probably not be an issue.

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

Now i have implemented the suggestion of Danny35d (thanks for this advise)

The only drawback is the second "do not use" parameter $iRunFirstTime (but that maybe the cost of the advantage in speed)

Isn't the existing "do not use" parameter, $sTWorkPath, only populated during a recursive call? I think "If Not $sTWorkPath Then" might replace "If $iRunFirstTime Then". Maybe park a comment on the end of the test saying "; bypass recursive calls" or "; process initial call only" or something similar.

About the SRER, I'd like someone to pipe up if there is a reason for it. I don't believe that FileFindNextFile ever returns a filename containing a trailing forward slash or backward slash. I'm not sure you conducted the test correctly, removing all four SRER statements and running a test with exclude enabled showed a major speed increase for me, consistantly.

Edit: With these latest additions, I'm now liking: _FileListToArrayTurbo4000PlusWithPowerboost()

Edited by Spiff59
Link to comment
Share on other sites

Isn't the existing "do not use" parameter, $sTWorkPath, only populated during a recursive call? I think "If Not $sTWorkPath Then" might replace "If $iRunFirstTime Then". Maybe park a comment on the end of the test saying "; bypass recursive calls" or "; process initial call only" or something similar.

No, it's only used if $iPathType = 1 (relative)

--> If $iPathType = 1 Then $sTWorkPath = $sWorkPath & $sFile & "\" <--, it's your code ;-)

About the SRER, I'd like someone to pipe up if there is a reason for it. I don't believe that FileFindNextFile ever returns a filename containing a trailing forward slash or backward slash. I'm not sure you conducted the test correctly, removing all four SRER statements and running a test with exclude enabled showed a major speed increase for me, consistantly.

I don't understand your question. Witch StringRegExpReplace do you mean?

There are some for different purposes.

Edit: With these latest additions, I'm now liking: _FileListToArrayTurbo4000PlusWithPowerboost()

Yes that's really good, this drives jpm mad ;-)
Link to comment
Share on other sites

No, it's only used if $iPathType = 1 (relative)

--> If $iPathType = 1 Then $sTWorkPath = $sWorkPath & $sFile & "\" <--, it's your code ;-)

Ahem, nice weather today, huh?

That's what I get for just spitting things out. Yes, it's only populated on recursive calls, but yes, also, it's only populated when PathType = 1 :)

Which StringRegExpReplace do you mean?

I think all 4 of these lines:

If StringRegExp(StringRegExpReplace($sFile, "(.*?[\\/]+)*(.*?\z)", "\2"), $sTExclude) Then ContinueLoop

may only need to be:

If StringRegExp($sFile, $sTExclude) Then ContinueLoop

Edit: I just ran the test here at work. So, at this point scanning my entire C: and D: drives at home, and this C: drive at work have yet to encounter one instance where those SRER statements made a single modification.

Edit2: Post 123 is not a benchmark but a test run. It forces exclusion, so isn't going to benchmark against a non-exclude run. It's simple meant to demonstrate, by not generating any MsgBox() windows (except the final file count), that the 4 exclude SRER's never do anything.

Edited by Spiff59
Link to comment
Share on other sites

If StringRegExp(StringRegExpReplace($sFile, "(.*?[\\/]+)*(.*?\z)", "\2"), $sTExclude) Then ContinueLoop

If StringRegExp($sFile, $sTExclude) Then ContinueLoop

Fantastic, you have won the jackpot!

My Test (quick and dirty, has to be tested more often)

(one path with 10584 files, 1560 folders, filter="*", return files/folders, full path, recursion, with one exclusion (folder exclusion), repeat 30 times):

_FileListToArrayNT3: Sec = 19.51 , 9719 items

_FileListToArrayNT4: Sec = 14.69 , 9719 items , oh that's nice

_FileListToArrayNT4 (or _FileListToArrayTurbo4000PlusWithUltraPowerboostbySpiff59)

; #FUNCTION# ===========================================================================================
; Name:             _FileListToArrayNT4
; Description:      full compatible _FileListToArray replacement  (with greater performance and additional features)
;                   additional: multi-path, multi-filter, multi-exclude-filter, path format options, recursive search
; Syntax:           _FileListToArrayNT4([$sPath = @ScriptDir, [$sFilter = "*", [$iSearchType, [$bRecursiv = False, [$sExclude = "", [$iRetFormat = 1]]]]]])
; Parameter(s):     $sPath = optional: Search path(s), semicolon delimited (default: @ScriptDir)
;                             (Example: "C:\Tmp;D:\Temp")
;                   $sFilter = optional: Search filter(s), semicolon delimited . Wildcards allowed. (default: "*")
;                              (Example: "*.exe;*.txt")
;                   $iSearchType = Include in search: 0 = Files and Folder, 1 = Files Only, 2 = Folders Only
;                   $iPathType = Returned element format: 0 = file/folder name only, 1 = relative path, 2 = full path
;                   $bRecursiv = optional: True: recursive search including all subdirectories
;                                          False (default): search only in specified folder
;                   $sExclude = optional: Exclude filter(s), semicolon delimited. Wildcards allowed.
;                                (Example: "Unins*" will remove all files/folders that begin with "Unins")
;                   $iRetFormat =  optional: return format
;                                  0 = one-dimensional array, 0-based
;                                  1 = one-dimensional array, 1-based (default)
;                                  2 = String ( "|" delimited)
;                   $sWorkPath =     *** internal use only (do not use) ***
;                   $bRunFirstTime = *** internal use only (do not use) ***
; Requirement(s):   none
; Return Value(s):  on success: 1-based or 0-based array or string (dependent on $iRetFormat)
;                   If no data is found, @error is set (to 4, for backwards compatibility)
; Author(s):        Half the AutoIt Community
; ====================================================================================================
Func _FileListToArrayNT4($sPath = @ScriptDir, $sFilter = "*", $iSearchType = 0, $iPathType = 0, $bRecursiv = False, $sExclude = "", $iRetFormat = 1, $sWorkPath = "", $bRunFirstTime = True)
  Local $hSearch, $iPCount, $iFCount, $sFile, $sFileList, $sTWorkPath

  If $bRunFirstTime Then
    If $sPath = -1 Or $sPath = Default Then $sPath = @ScriptDir
    If $sFilter = -1 Or $sFilter = Default Then $sFilter = "*"
    If $iSearchType = -1 Or $iSearchType = Default Then $iSearchType = 0
    If $iPathType = -1 Or $iPathType = Default Then $iPathType = 0
    If $bRecursiv = Default Then $bRecursiv = False
    If $sExclude = -1 Or $sExclude = Default Then $sExclude = ""
    If $iRetFormat = -1 Or $iRetFormat = Default Then $iRetFormat = 1

    If $sExclude Then
      ;prepare $sExclude
      ;strip leading and trailing spaces and spaces between semi colon delimiter
      $sExclude = StringStripWS(StringRegExpReplace($sExclude, "\s*;\s*", ";"), 3)
      ;convert $sExclude to fit StringRegExp (not perfect but useable)
      $sExclude = StringRegExpReplace($sExclude, '([\Q\.+[^]$(){}=!\E])', '\\$1') ;thanks KaFu and Ascend4nt
      $sExclude = StringReplace($sExclude, "?", ".")
      $sExclude = StringReplace($sExclude, "*", ".*?")
      $sExclude = "(?i)\A" & StringReplace($sExclude, ";", "|") & "\z"
    EndIf

    ;strip leading and trailing spaces and spaces between semi colon delimiter
    $sPath = StringStripWS(StringRegExpReplace($sPath, "\s*;\s*", ";"), 3)
    $sFilter = StringStripWS(StringRegExpReplace($sFilter, "\s*;\s*", ";"), 3)

    $bRunFirstTime = False
  EndIf

  Local $aPath = StringSplit($sPath, ';', 1) ;paths array
  Local $aFilter = StringSplit($sFilter, ';', 1) ;filters array

  If $sExclude Then

    For $iPCount = 1 To $aPath[0] ;Path loop
      Local $sDelim = "|" ;reset $sDelim

      If StringRight($aPath[$iPCount], 1) <> "\" Then $aPath[$iPCount] &= "\" ;ensure trailing slash

      If $iPathType = 2 Then $sDelim &= $aPath[$iPCount] ;return full-path

      For $iFCount = 1 To $aFilter[0] ;Filter loop
        If StringRegExp($aFilter[$iFCount], "[\\/:<>|]") Then ContinueLoop ;bypass filters with invalid chars
        $hSearch = FileFindFirstFile($aPath[$iPCount] & $aFilter[$iFCount])
        If @error Then ContinueLoop
        Switch $iSearchType
          Case 1 ;files Only
            While True
              $sFile = FileFindNextFile($hSearch)
              If @error Then ExitLoop
              If @extended Then ContinueLoop ;bypass folder
              ;check for exclude files
              If StringRegExp($sFile, $sExclude) Then ContinueLoop
              $sFileList &= $sDelim & $sWorkPath & $sFile
            WEnd
          Case 2 ;folders Only
            While True
              $sFile = FileFindNextFile($hSearch)
              If @error Then ExitLoop
              If @extended = 0 Then ContinueLoop ;bypass file
              ;check for exclude folder
              If StringRegExp($sFile, $sExclude) Then ContinueLoop
              $sFileList &= $sDelim & $sWorkPath & $sFile
            WEnd
          Case Else ;files and folders
            While True
              $sFile = FileFindNextFile($hSearch)
              If @error Then ExitLoop
              ;check for exclude files/folder
              If StringRegExp($sFile, $sExclude) Then ContinueLoop
              $sFileList &= $sDelim & $sWorkPath & $sFile
            WEnd
        EndSwitch
        FileClose($hSearch)
      Next ;$iFCount - next filter

      ;---------------

      ;optional do a recursive search
      If $bRecursiv Then
        $hSearch = FileFindFirstFile($aPath[$iPCount] & "*.*")
        If Not @error Then
          While True
            $sFile = FileFindNextFile($hSearch)
            If @error Then ExitLoop
            If @extended = 0 Then ContinueLoop ;bypass file (for Autoit versions > 3.3.0.0)
            ;check for exclude folder
            If StringRegExp($sFile, $sExclude) Then ContinueLoop
            ;call recursive search
            If $iPathType = 1 Then $sTWorkPath = $sWorkPath & $sFile & "\"
            $sFileList &= _FileListToArrayNT4($aPath[$iPCount] & $sFile & "\", $sFilter, $iSearchType, $iPathType, $bRecursiv, $sExclude, 2, $sTWorkPath, $bRunFirstTime)
          WEnd
          FileClose($hSearch)
        EndIf
      EndIf

    Next ;$iPCount - next path

  Else ;If Not $sExclude

    For $iPCount = 1 To $aPath[0] ;path loop
      Local $sDelim = "|" ;reset $sDelim

      If StringRight($aPath[$iPCount], 1) <> "\" Then $aPath[$iPCount] &= "\" ;ensure trailing slash

      ;return full-path
      If $iPathType = 2 Then $sDelim &= $aPath[$iPCount]

      ;perform the search
      For $iFCount = 1 To $aFilter[0] ;Filter loop
        If StringRegExp($aFilter[$iFCount], "[\\/:<>|]") Then ContinueLoop ;bypass filters with invalid chars
        $hSearch = FileFindFirstFile($aPath[$iPCount] & $aFilter[$iFCount])
        If @error Then ContinueLoop
        Switch $iSearchType
          Case 1 ;files Only
            While True
              $sFile = FileFindNextFile($hSearch)
              If @error Then ExitLoop
              If @extended Then ContinueLoop ;bypass folder
              $sFileList &= $sDelim & $sWorkPath & $sFile
            WEnd
          Case 2 ;folders Only
            While True
              $sFile = FileFindNextFile($hSearch)
              If @error Then ExitLoop
              If @extended = 0 Then ContinueLoop ;bypass file
              $sFileList &= $sDelim & $sWorkPath & $sFile
            WEnd
          Case Else ;files and folders
            While True
              $sFile = FileFindNextFile($hSearch)
              If @error Then ExitLoop
              $sFileList &= $sDelim & $sWorkPath & $sFile
            WEnd
        EndSwitch
        FileClose($hSearch)
      Next ;$iFCount - next filter

      ;---------------

      ;optional do a recursive search
      If $bRecursiv Then
        $hSearch = FileFindFirstFile($aPath[$iPCount] & "*.*")
        If Not @error Then
          While True
            $sFile = FileFindNextFile($hSearch)
            If @error Then ExitLoop
            If @extended = 0 Then ContinueLoop ;bypass file (for Autoit versions > 3.3.0.0)
            ;call recursive search
            If $iPathType = 1 Then $sTWorkPath = $sWorkPath & $sFile & "\"
            $sFileList &= _FileListToArrayNT4($aPath[$iPCount] & $sFile & "\", $sFilter, $iSearchType, $iPathType, $bRecursiv, $sExclude, 2, $sTWorkPath, $bRunFirstTime)
          WEnd
          FileClose($hSearch)
        EndIf
      EndIf

    Next ;$iPCount - next path

  EndIf ;If $sExclude

  ;---------------

  ;set according return value
  If $sFileList Then
    Switch $iRetFormat
      Case 2 ;return a delimited string
        Return $sFileList
      Case 0 ;return a 0-based array
        Return StringSplit(StringTrimLeft($sFileList, 1), "|", 2)
      Case Else ;return a 1-based array
        Return StringSplit(StringTrimLeft($sFileList, 1), "|", 1)
    EndSwitch
  Else
    Return SetError(4, 4, "")
  EndIf

EndFunc   ;==>_FileListToArrayNT4
Edited by BaKaMu
Link to comment
Share on other sites

_FileListToArrayNT4 (or _FileListToArrayTurbo4000PlusWithUltraPowerboostbySpiff59)

I don't need my name up in lights, but I do think we're missing a "Pro" in there, so:

_FileListToArrayTurbo4000PlusProWithUltraPowerboost

:)

BTW: Have you tried running Post #123 against the biggest hard drive you have? Does it make it to the file-count message without any other messages? I'm almost positive that FileFindNextFile never returns a string with a trailing slash and that the last change stripping off the SRER's is valid.

Edited by Spiff59
Link to comment
Share on other sites

I don't need my name up in lights, but I do think we're missing a "Pro" in there, so:

_FileListToArrayTurbo4000PlusProWithUltraPowerboost

Agree :-)

BTW: Have you tried running Post #123 against the biggest hard drive you have? Does it make it to the file-count message without any other messages? I'm almost positive that FileFindNextFile never returns a string with a trailing slash and that the last change stripping off the SRER's is valid.

No, but i belief that stripping off the SRER's is valid.

This StringRegExp(StringRegExpReplace($sFile, "(.*?[\\/]+)*(.*?\z)", "\2"), $sExclude) combination splits a full path in path and file/folder name and then compares to $sExclude.

FileFindNextFile only returns file or folder name so stripping off the SRER's can not be invalid (theoretical).

Hopefully we have reached the limit now. ;-)

After all i have to relax a little bit.

Edited by BaKaMu
Link to comment
Share on other sites

  • Moderators

Without going through every piece of code you've written here. Have ya'll tried just condition statements without ContinueLoop overhead? I don't know how much has changed with it, but I've found in the past that:

If @error = 0 Then
   ;Condition
EndIf

Is much faster for large loops than:

If @error Then ContinueLoop

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

If @error = 0 Then ... Condition ... EndIf

Is much faster for large loops than:

If @error Then ContinueLoop

Good idea an i have made some tests with this suggestion.

Yes: If Condition Then ... EndIf is faster then If Condition Then ContinueLoop

But: If the condition is a negation (ex Not @error or Not StringRegExp(...)) then it is slower.

So in _FileListToArrayNT5 i have paid attention to not using negation.

And Voila, there is a little speed improvement.

(but really little compared to Spiff59 boosting)

Test1 (one path with 10584 files, 1560 folders, filter="*", return files/folders, full path, recursion, with no exclusion, repeat 30 times):

_FileListToArrayNT4: Sec = 16.21 , 12144 items

_FileListToArrayNT5: Sec = 16.01 , 12144 items

Test2 (one path with 10584 files, 1560 folders, filter="*", return files/folders, full path, recursion, with one exclusion (folder exclusion), repeat 30 times):

_FileListToArrayNT4: Sec = 14.71 , 9719 items

_FileListToArrayNT5: Sec = 14.65 , 9719 items

I thought we have reached the limit now, but obviously not. Thank you SmOke_N ;-)

_FileListToArrayNT5 (@Spiff59: _FileListToArrayTurbo4000PlusProWithMoreUltraPowerboost)

; #FUNCTION# ===========================================================================================
; Name:             _FileListToArrayNT5
; Description:      full compatible _FileListToArray replacement  (with greater performance and additional features)
;                   additional: multi-path, multi-filter, multi-exclude-filter, path format options, recursive search
; Syntax:           _FileListToArrayNT5([$sPath = @ScriptDir, [$sFilter = "*", [$iSearchType, [$bRecursiv = False, [$sExclude = "", [$iRetFormat = 1]]]]]])
; Parameter(s):     $sPath = optional: Search path(s), semicolon delimited (default: @ScriptDir)
;                             (Example: "C:\Tmp;D:\Temp")
;                   $sFilter = optional: Search filter(s), semicolon delimited . Wildcards allowed. (default: "*")
;                              (Example: "*.exe;*.txt")
;                   $iSearchType = Include in search: 0 = Files and Folder, 1 = Files Only, 2 = Folders Only
;                   $iPathType = Returned element format: 0 = file/folder name only, 1 = relative path, 2 = full path
;                   $bRecursiv = optional: True: recursive search including all subdirectories
;                                          False (default): search only in specified folder
;                   $sExclude = optional: Exclude filter(s), semicolon delimited. Wildcards allowed.
;                                (Example: "Unins*" will remove all files/folders that begin with "Unins")
;                   $iRetFormat =  optional: return format
;                                  0 = one-dimensional array, 0-based
;                                  1 = one-dimensional array, 1-based (default)
;                                  2 = String ( "|" delimited)
;                   $sWorkPath =     *** internal use only (do not use) ***
;                   $bRunFirstTime = *** internal use only (do not use) ***
; Requirement(s):   none
; Return Value(s):  on success: 1-based or 0-based array or string (dependent on $iRetFormat)
;                   If no data is found, @error is set (to 4, for backwards compatibility)
; Author(s):        Half the AutoIt Community
; ====================================================================================================
Func _FileListToArrayNT5($sPath = @ScriptDir, $sFilter = "*", $iSearchType = 0, $iPathType = 0, $bRecursiv = False, $sExclude = "", $iRetFormat = 1, $sWorkPath = "", $bRunFirstTime = True)
  Local $hSearch, $iPCount, $iFCount, $sFile, $sFileList, $sTWorkPath

  If $bRunFirstTime Then
    If $sPath = -1 Or $sPath = Default Then $sPath = @ScriptDir
    If $sFilter = -1 Or $sFilter = Default Then $sFilter = "*"
    If $iSearchType = -1 Or $iSearchType = Default Then $iSearchType = 0
    If $iPathType = -1 Or $iPathType = Default Then $iPathType = 0
    If $bRecursiv = Default Then $bRecursiv = False
    If $sExclude = -1 Or $sExclude = Default Then $sExclude = ""
    If $iRetFormat = -1 Or $iRetFormat = Default Then $iRetFormat = 1

    If $sExclude Then
      ;prepare $sExclude
      ;strip leading and trailing spaces and spaces between semi colon delimiter
      $sExclude = StringStripWS(StringRegExpReplace($sExclude, "\s*;\s*", ";"), 3)
      ;convert $sExclude to fit StringRegExp (not perfect but useable)
      $sExclude = StringRegExpReplace($sExclude, '([\Q\.+[^]$(){}=!\E])', '\\$1') ;thanks KaFu and Ascend4nt
      $sExclude = StringReplace($sExclude, "?", ".")
      $sExclude = StringReplace($sExclude, "*", ".*?")
      $sExclude = "(?i)\A" & StringReplace($sExclude, ";", "|") & "\z"
    EndIf

    ;strip leading and trailing spaces and spaces between semi colon delimiter
    $sPath = StringStripWS(StringRegExpReplace($sPath, "\s*;\s*", ";"), 3)
    $sFilter = StringStripWS(StringRegExpReplace($sFilter, "\s*;\s*", ";"), 3)

    $bRunFirstTime = False
  EndIf

  Local $aPath = StringSplit($sPath, ';', 1) ;paths array
  Local $aFilter = StringSplit($sFilter, ';', 1) ;filters array

  If $sExclude Then

    For $iPCount = 1 To $aPath[0] ;Path loop
      Local $sDelim = "|" ;reset $sDelim

      If StringRight($aPath[$iPCount], 1) <> "\" Then $aPath[$iPCount] &= "\" ;ensure trailing slash

      If $iPathType = 2 Then $sDelim &= $aPath[$iPCount] ;return full-path

      For $iFCount = 1 To $aFilter[0] ;Filter loop
        If StringRegExp($aFilter[$iFCount], "[\\/:<>|]") Then ContinueLoop ;bypass filters with invalid chars
        $hSearch = FileFindFirstFile($aPath[$iPCount] & $aFilter[$iFCount])
        If @error Then ContinueLoop
        Switch $iSearchType
          Case 1 ;files Only
            While True
              $sFile = FileFindNextFile($hSearch)
              If @error Then ExitLoop
              If @extended Then ContinueLoop ;bypass folder
              ;check for exclude files
              If StringRegExp($sFile, $sExclude) Then ContinueLoop
              $sFileList &= $sDelim & $sWorkPath & $sFile
            WEnd
          Case 2 ;folders Only
            While True
              $sFile = FileFindNextFile($hSearch)
              If @error Then ExitLoop
              If @extended Then ;bypass file
                ;check for exclude folder
                If StringRegExp($sFile, $sExclude) Then ContinueLoop
                $sFileList &= $sDelim & $sWorkPath & $sFile
              EndIf
            WEnd
          Case Else ;files and folders
            While True
              $sFile = FileFindNextFile($hSearch)
              If @error Then ExitLoop
              ;check for exclude files/folder
              If StringRegExp($sFile, $sExclude) Then ContinueLoop
              $sFileList &= $sDelim & $sWorkPath & $sFile
            WEnd
        EndSwitch
        FileClose($hSearch)
      Next ;$iFCount - next filter

      ;---------------

      ;optional do a recursive search
      If $bRecursiv Then
        $hSearch = FileFindFirstFile($aPath[$iPCount] & "*.*")
        If Not @error Then
          While True
            $sFile = FileFindNextFile($hSearch)
            If @error Then ExitLoop
            If @extended Then ;bypass file (for Autoit versions > 3.3.0.0)
              ;check for exclude folder
              If StringRegExp($sFile, $sExclude) Then ContinueLoop
              ;call recursive search
              If $iPathType = 1 Then $sTWorkPath = $sWorkPath & $sFile & "\"
              $sFileList &= _FileListToArrayNT5($aPath[$iPCount] & $sFile & "\", $sFilter, $iSearchType, $iPathType, $bRecursiv, $sExclude, 2, $sTWorkPath, $bRunFirstTime)
            EndIf
          WEnd
          FileClose($hSearch)
        EndIf
      EndIf

    Next ;$iPCount - next path

  Else ;If Not $sExclude

    For $iPCount = 1 To $aPath[0] ;path loop
      Local $sDelim = "|" ;reset $sDelim

      If StringRight($aPath[$iPCount], 1) <> "\" Then $aPath[$iPCount] &= "\" ;ensure trailing slash

      ;return full-path
      If $iPathType = 2 Then $sDelim &= $aPath[$iPCount]

      ;perform the search
      For $iFCount = 1 To $aFilter[0] ;Filter loop
        If StringRegExp($aFilter[$iFCount], "[\\/:<>|]") Then ContinueLoop ;bypass filters with invalid chars
        $hSearch = FileFindFirstFile($aPath[$iPCount] & $aFilter[$iFCount])
        If @error Then ContinueLoop
        Switch $iSearchType
          Case 1 ;files Only
            While True
              $sFile = FileFindNextFile($hSearch)
              If @error Then ExitLoop
              If @extended Then ContinueLoop ;bypass folder
              $sFileList &= $sDelim & $sWorkPath & $sFile
            WEnd
          Case 2 ;folders Only
            While True
              $sFile = FileFindNextFile($hSearch)
              If @error Then ExitLoop
              If @extended Then ;bypass file
                $sFileList &= $sDelim & $sWorkPath & $sFile
              EndIf
            WEnd
          Case Else ;files and folders
            While True
              $sFile = FileFindNextFile($hSearch)
              If @error Then ExitLoop
              $sFileList &= $sDelim & $sWorkPath & $sFile
            WEnd
        EndSwitch
        FileClose($hSearch)
      Next ;$iFCount - next filter

      ;---------------

      ;optional do a recursive search
      If $bRecursiv Then
        $hSearch = FileFindFirstFile($aPath[$iPCount] & "*.*")
        If Not @error Then
          While True
            $sFile = FileFindNextFile($hSearch)
            If @error Then ExitLoop
            If @extended Then ;bypass file (for Autoit versions > 3.3.0.0)
              ;call recursive search
              If $iPathType = 1 Then $sTWorkPath = $sWorkPath & $sFile & "\"
              $sFileList &= _FileListToArrayNT5($aPath[$iPCount] & $sFile & "\", $sFilter, $iSearchType, $iPathType, $bRecursiv, $sExclude, 2, $sTWorkPath, $bRunFirstTime)
            EndIf
          WEnd
          FileClose($hSearch)
        EndIf
      EndIf

    Next ;$iPCount - next path

  EndIf ;If $sExclude

  ;---------------

  ;set according return value
  If $sFileList Then
    Switch $iRetFormat
      Case 2 ;return a delimited string
        Return $sFileList
      Case 0 ;return a 0-based array
        Return StringSplit(StringTrimLeft($sFileList, 1), "|", 2)
      Case Else ;return a 1-based array
        Return StringSplit(StringTrimLeft($sFileList, 1), "|", 1)
    EndSwitch
  Else
    Return SetError(4, 4, "")
  EndIf

EndFunc   ;==>_FileListToArrayNT5
Edited by BaKaMu
Link to comment
Share on other sites

  • Moderators

Good idea an i have made some tests with this suggestion.

Yes: If Condition Then ... EndIf is faster then If Condition Then ContinueLoop

But: If the condition is a negation (ex Not @error or Not StringRegExp(...)) then it is slower.

So in _FileListToArrayNT5 i have paid attention to not using negation.

And Voila, there is a little speed improvement.

(but really little compared to Spiff59 boosting)

Test1 (one path with 10584 files, 1560 folders, filter="*", return files/folders, full path, recursion, with no exclusion, repeat 30 times):

_FileListToArrayNT4: Sec = 16.21 , 12144 items

_FileListToArrayNT5: Sec = 16.01 , 12144 items

Test2 (one path with 10584 files, 1560 folders, filter="*", return files/folders, full path, recursion, with one exclusion (folder exclusion), repeat 30 times):

_FileListToArrayNT4: Sec = 14.71 , 9719 items

_FileListToArrayNT5: Sec = 14.65 , 9719 items

I thought we have reached the limit now, but obviously not. Thank you SmOke_N ;-)

_FileListToArrayNT5 (@Spiff59: _FileListToArrayTurbo4000PlusProWithMoreUltraPowerboost)

This is actually what I had in mind:
; #FUNCTION# ===========================================================================================
; Name:             _FileListToArrayNT5
; Description:      full compatible _FileListToArray replacement  (with greater performance and additional features)
;                   additional: multi-path, multi-filter, multi-exclude-filter, path format options, recursive search
; Syntax:           _FileListToArrayNT5([$sPath = @ScriptDir, [$sFilter = "*", [$iSearchType, [$bRecursiv = False, [$sExclude = "", [$iRetFormat = 1]]]]]])
; Parameter(s):     $sPath = optional: Search path(s), semicolon delimited (default: @ScriptDir)
;                             (Example: "C:\Tmp;D:\Temp")
;                   $sFilter = optional: Search filter(s), semicolon delimited . Wildcards allowed. (default: "*")
;                              (Example: "*.exe;*.txt")
;                   $iSearchType = Include in search: 0 = Files and Folder, 1 = Files Only, 2 = Folders Only
;                   $iPathType = Returned element format: 0 = file/folder name only, 1 = relative path, 2 = full path
;                   $bRecursiv = optional: True: recursive search including all subdirectories
;                                          False (default): search only in specified folder
;                   $sExclude = optional: Exclude filter(s), semicolon delimited. Wildcards allowed.
;                                (Example: "Unins*" will remove all files/folders that begin with "Unins")
;                   $iRetFormat =  optional: return format
;                                  0 = one-dimensional array, 0-based
;                                  1 = one-dimensional array, 1-based (default)
;                                  2 = String ( "|" delimited)
;                   $sWorkPath =     *** internal use only (do not use) ***
;                   $bRunFirstTime = *** internal use only (do not use) ***
; Requirement(s):   none
; Return Value(s):  on success: 1-based or 0-based array or string (dependent on $iRetFormat)
;                   If no data is found, @error is set (to 4, for backwards compatibility)
; Author(s):        Half the AutoIt Community
; ====================================================================================================

Func _FileListToArrayNT5($sPath = @ScriptDir, $sFilter = "*", $iSearchType = 0, $iPathType = 0, $bRecursiv = False, $sExclude = "", $iRetFormat = 1, $sWorkPath = "", $bRunFirstTime = True)
    Local $hSearch, $iPCount, $iFCount, $sFile, $sFileList, $sTWorkPath

    If $bRunFirstTime Then
        If $sPath = -1 Or $sPath = Default Then $sPath = @ScriptDir
        If $sFilter = -1 Or $sFilter = Default Then $sFilter = "*"
        If $iSearchType = -1 Or $iSearchType = Default Then $iSearchType = 0
        If $iPathType = -1 Or $iPathType = Default Then $iPathType = 0
        If $bRecursiv = Default Then $bRecursiv = False
        If $sExclude = -1 Or $sExclude = Default Then $sExclude = ""
        If $iRetFormat = -1 Or $iRetFormat = Default Then $iRetFormat = 1

        If $sExclude Then
            ;prepare $sExclude
            ;strip leading and trailing spaces and spaces between semi colon delimiter
            $sExclude = StringStripWS(StringRegExpReplace($sExclude, "\s*;\s*", ";"), 3)
            ;convert $sExclude to fit StringRegExp (not perfect but useable)
            $sExclude = StringRegExpReplace($sExclude, '([\Q\.+[^]$(){}=!\E])', '\\$1') ;thanks KaFu and Ascend4nt
            $sExclude = StringReplace($sExclude, "?", ".")
            $sExclude = StringReplace($sExclude, "*", ".*?")
            $sExclude = "(?i)\A" & StringReplace($sExclude, ";", "|") & "\z"
        EndIf

        ;strip leading and trailing spaces and spaces between semi colon delimiter
        $sPath = StringStripWS(StringRegExpReplace($sPath, "\s*;\s*", ";"), 3)
        $sFilter = StringStripWS(StringRegExpReplace($sFilter, "\s*;\s*", ";"), 3)

        $bRunFirstTime = False
    EndIf

    Local $aPath = StringSplit($sPath, ';', 1) ;paths array
    Local $aFilter = StringSplit($sFilter, ';', 1) ;filters array

    If $sExclude Then

        For $iPCount = 1 To $aPath[0] ;Path loop
            Local $sDelim = "|" ;reset $sDelim

            If StringRight($aPath[$iPCount], 1) <> "\" Then $aPath[$iPCount] &= "\" ;ensure trailing slash

            If $iPathType = 2 Then $sDelim &= $aPath[$iPCount] ;return full-path

            For $iFCount = 1 To $aFilter[0] ;Filter loop
                If StringRegExp($aFilter[$iFCount], "[\\/:<>|]") = 0 Then ;bypass filters with invalid chars
                    $hSearch = FileFindFirstFile($aPath[$iPCount] & $aFilter[$iFCount])
                    If @error Then ContinueLoop
                    Switch $iSearchType
                        Case 1 ;files Only
                            While True
                                $sFile = FileFindNextFile($hSearch)
                                If @error Then ExitLoop
                                If @extended = 0 Then
                                    ;check for exclude files
                                    If StringRegExp($sFile, $sExclude) = 0 Then
                                        $sFileList &= $sDelim & $sWorkPath & $sFile
                                    EndIf
                                EndIf
                            WEnd
                        Case 2 ;folders Only
                            While True
                                $sFile = FileFindNextFile($hSearch)
                                If @error Then ExitLoop
                                If @extended Then ;bypass file
                                    ;check for exclude folder
                                    If StringRegExp($sFile, $sExclude) = 0 Then
                                        $sFileList &= $sDelim & $sWorkPath & $sFile
                                    EndIf
                                EndIf
                            WEnd
                        Case Else ;files and folders
                            While True
                                $sFile = FileFindNextFile($hSearch)
                                If @error Then ExitLoop
                                ;check for exclude files/folder
                                If StringRegExp($sFile, $sExclude) = 0 Then
                                    $sFileList &= $sDelim & $sWorkPath & $sFile
                                EndIf
                            WEnd
                    EndSwitch
                    FileClose($hSearch)
                EndIf
            Next ;$iFCount - next filter

            ;---------------

            ;optional do a recursive search
            If $bRecursiv Then
                $hSearch = FileFindFirstFile($aPath[$iPCount] & "*.*")
                If Not @error Then
                    While True
                        $sFile = FileFindNextFile($hSearch)
                        If @error Then ExitLoop
                        If @extended Then ;bypass file (for Autoit versions > 3.3.0.0)
                            ;check for exclude folder
                            If StringRegExp($sFile, $sExclude) = 0 Then
                                ;call recursive search
                                If $iPathType = 1 Then $sTWorkPath = $sWorkPath & $sFile & "\"
                                $sFileList &= _FileListToArrayNT5($aPath[$iPCount] & $sFile & "\", $sFilter, $iSearchType, $iPathType, $bRecursiv, $sExclude, 2, $sTWorkPath, $bRunFirstTime)
                            EndIf
                        EndIf
                    WEnd
                    FileClose($hSearch)
                EndIf
            EndIf

        Next ;$iPCount - next path

    Else ;If Not $sExclude

        For $iPCount = 1 To $aPath[0] ;path loop
            Local $sDelim = "|" ;reset $sDelim

            If StringRight($aPath[$iPCount], 1) <> "\" Then $aPath[$iPCount] &= "\" ;ensure trailing slash

            ;return full-path
            If $iPathType = 2 Then $sDelim &= $aPath[$iPCount]

            ;perform the search
            For $iFCount = 1 To $aFilter[0] ;Filter loop
                If StringRegExp($aFilter[$iFCount], "[\\/:<>|]") = 0 Then
                    $hSearch = FileFindFirstFile($aPath[$iPCount] & $aFilter[$iFCount])
                    If @error Then ContinueLoop
                    Switch $iSearchType
                        Case 1 ;files Only
                            While True
                                $sFile = FileFindNextFile($hSearch)
                                If @error Then ExitLoop
                                If @extended = 0 Then ;bypass folder
                                    $sFileList &= $sDelim & $sWorkPath & $sFile
                                EndIf
                            WEnd
                        Case 2 ;folders Only
                            While True
                                $sFile = FileFindNextFile($hSearch)
                                If @error Then ExitLoop
                                If @extended Then ;bypass file
                                    $sFileList &= $sDelim & $sWorkPath & $sFile
                                EndIf
                            WEnd
                        Case Else ;files and folders
                            While True
                                $sFile = FileFindNextFile($hSearch)
                                If @error Then ExitLoop
                                $sFileList &= $sDelim & $sWorkPath & $sFile
                            WEnd
                    EndSwitch
                    FileClose($hSearch)
                EndIf
            Next ;$iFCount - next filter

            ;---------------

            ;optional do a recursive search
            If $bRecursiv Then
                $hSearch = FileFindFirstFile($aPath[$iPCount] & "*.*")
                If Not @error Then
                    While True
                        $sFile = FileFindNextFile($hSearch)
                        If @error Then ExitLoop
                        If @extended Then ;bypass file (for Autoit versions > 3.3.0.0)
                            ;call recursive search
                            If $iPathType = 1 Then $sTWorkPath = $sWorkPath & $sFile & "\"
                            $sFileList &= _FileListToArrayNT5($aPath[$iPCount] & $sFile & "\", $sFilter, $iSearchType, $iPathType, $bRecursiv, $sExclude, 2, $sTWorkPath, $bRunFirstTime)
                        EndIf
                    WEnd
                    FileClose($hSearch)
                EndIf
            EndIf

        Next ;$iPCount - next path

    EndIf ;If $sExclude

    ;---------------

    ;set according return value
    If $sFileList Then
        Switch $iRetFormat
            Case 2 ;return a delimited string
                Return $sFileList
            Case 0 ;return a 0-based array
                Return StringSplit(StringTrimLeft($sFileList, 1), "|", 2)
            Case Else ;return a 1-based array
                Return StringSplit(StringTrimLeft($sFileList, 1), "|", 1)
        EndSwitch
    Else
        Return SetError(4, 4, "")
    EndIf

EndFunc   ;==>_FileListToArrayNT5
(Nothing checked other than ContinueLoop)

Edit:

Am I calling this the wrong way?

$a = _FileListToArrayNT5(@WindowsDir, "*", 0, 0, True)
If IsArray($a) Then ConsoleWrite($a[0] & @CRLF)
? There should be 5400+ files, and it only returns 300?

Edit2:

Nevermind, I made a "Beta" mistake :) ....

Edited by SmOke_N

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

This is actually what I had in mind:

(Nothing checked other than ContinueLoop)

That's the trick:

Sometimes --> If Condition Then ... EndIf <-- is faster and sometimes --> If Condition Then ContinueLoop <--

(depends on condition: conditions with negation or value checking make instruction slower,

so the advantage of --> If ... Then ... EndIf <-- will be nullified.

(i know that's hard to belief)

Link to comment
Share on other sites

I think I'm about done!

Just a few more things...

1. The block of parameter edit statements don't quite function as well as they could. I worked on them a little and came up with some changes. The test program below demonstrates the changes. Run that, the window titles describe pretty well what you're seeing. I think the new behavior is preferable and would like to see the old block of edits statements replaced with the new. (The main improvements are in the handling of empty strings, $bRecursive, and garbage data)

CODE
#include <GuiListView.au3>

; If StringRegExp($sPath, "(?i)Default$|-1|^$") Then $sPath = @ScriptDir
; The above worked to peg "Default", "-1" and "", but... is much slower!



Global $t1, $t2, $comment = "No parms specified"
_TestNT5()

$comment = "Empty strings"
$sPath = ""
$sFilter = ""
$iSearchType = ""
$iPathType = ""
$bRecursive = ""
$sExclude = ""
$iRetFormat = ""
_TestNT5($sPath, $sFilter, $iSearchType, $iPathType, $bRecursive, $sExclude, $iRetFormat)

$comment = "Everything is Default"
$sPath = Default
$sFilter = Default
$iSearchType = Default
$iPathType = Default
$bRecursive = Default
$sExclude = Default
$iRetFormat = Default
_TestNT5($sPath, $sFilter, $iSearchType, $iPathType, $bRecursive, $sExclude, $iRetFormat)

$comment = "Everything is True"
$sPath = True
$sFilter = True
$iSearchType = True
$iPathType = True
$bRecursive = True
$sExclude = True
$iRetFormat = True
_TestNT5($sPath, $sFilter, $iSearchType, $iPathType, $bRecursive, $sExclude, $iRetFormat)

$comment = "Everything is False"
$sPath = False
$sFilter = False
$iSearchType = False
$iPathType = False
$bRecursive = False
$sExclude = False
$iRetFormat = False
_TestNT5($sPath, $sFilter, $iSearchType, $iPathType, $bRecursive, $sExclude, $iRetFormat)

$comment = "Everything is 0"
$sPath = 0
$sFilter = 0
$iSearchType = 0
$iPathType = 0
$bRecursive = 0
$sExclude = 0
$iRetFormat = 0
_TestNT5($sPath, $sFilter, $iSearchType, $iPathType, $bRecursive, $sExclude, $iRetFormat)

$comment = "Everything is 1"
$sPath = 1
$sFilter = 1
$iSearchType = 1
$iPathType = 1
$bRecursive = 1
$sExclude = 1
$iRetFormat = 1
_TestNT5($sPath, $sFilter, $iSearchType, $iPathType, $bRecursive, $sExclude, $iRetFormat)

$comment = "Everything is -1"
$sPath = -1
$sFilter = -1
$iSearchType = -1
$iPathType = -1
$bRecursive = -1
$sExclude = -1
$iRetFormat = -1
_TestNT5($sPath, $sFilter, $iSearchType, $iPathType, $bRecursive, $sExclude, $iRetFormat)

$comment = "All Garbage"
$sPath = "Nothin' but garbage"
$sFilter = "xyzzy"
$iSearchType = "plugh"
$iPathType = "plover"
$bRecursive = "42"
$sExclude = "xyz"
$iRetFormat = "123"
_TestNT5($sPath, $sFilter, $iSearchType, $iPathType, $bRecursive, $sExclude, $iRetFormat)

MsgBox(1,"1000 iterations in milliseconds","Old edits: " & $t1 & @CRLF & "New edits: " & $t2 & @CRLF & "Difference per call in millionths of a second: " & Int($t2 - $t1))
Exit

;===============================================================================
Func _TestNT5($sPath = @ScriptDir, $sFilter = "*", $iSearchType = 0, $iPathType = 0, $bRecursive = False, $sExclude = "", $iRetFormat = 1)


    GuiCreate("Row 1: Parms in  Row 2: Old edits    Row 3: New edits        (" & $comment & ")", 800, 110)
    $ListView = GuiCtrlCreateListView("$sPath|$sFilter|$iSearch|$iPath|$bRec|$sExclude|$iRet", 10, 15, 780, 90)
    _GUICtrlListView_SetColumnWidth ($ListView, 0, 295)
    _GUICtrlListView_SetColumnWidth ($ListView, 1, 120)
    _GUICtrlListView_SetColumnWidth ($ListView, 2, 60)
    _GUICtrlListView_SetColumnWidth ($ListView, 3, 60)
    _GUICtrlListView_SetColumnWidth ($ListView, 4, 60)
    _GUICtrlListView_SetColumnWidth ($ListView, 5, 120)
    _GUICtrlListView_SetColumnWidth ($ListView, 6, 60)
    GUISetState ()

; DISPLAY PARMS IN ---------------------------------------------------------------------
    GuiCtrlCreateListViewItem($sPath & "|" & $sFilter & "|" & $iSearchType & "|" & $iPathType & "|" & $bRecursive & "|" & $sExclude & "|" & $iRetFormat, $ListView)

; store original parms ----------------------------------------------------------
    $save_sPath = $sPath
    $save_sFilter = $sFilter
    $save_iSearchType = $iSearchType
    $save_iPathType = $iPathType
    $save_bRecursiv = $bRecursive
    $save_sExclude = $sExclude
    $save_iRetFormat = $iRetFormat

; old parameters edits -----------------------------------------------
    $t1 = TimerInit()
    For $x = 1 to 1000
        If $sPath = -1 Or $sPath = Default Then $sPath = @ScriptDir
        If $sFilter = -1 Or $sFilter = Default Then $sFilter = "*"
        If $iSearchType = -1 Or $iSearchType = Default Then $iSearchType = 0
        If $iPathType = -1 Or $iPathType = Default Then $iPathType = 0
        If $bRecursive = Default Then $bRecursive = False
        If $sExclude = -1 Or $sExclude = Default Then $sExclude = ""
        If $iRetFormat = -1 Or $iRetFormat = Default Then $iRetFormat = 1
    Next
    $t1 = TimerDiff($t1)
    GuiCtrlCreateListViewItem($sPath & "|" & $sFilter & "|" & $iSearchType & "|" & $iPathType & "|" & $bRecursive & "|" & $sExclude & "|" & $iRetFormat, $ListView)

; restore original parms -------------------------------------------------------
    $sPath = $save_sPath
    $sFilter = $save_sFilter
    $iSearchType = $save_iSearchType
    $iPathType = $save_iPathType
    $bRecursive = $save_bRecursiv
    $sExclude = $save_sExclude
    $iRetFormat = $save_iRetFormat

; new parameter edits ------------------------------------------------
    $t2 = TimerInit()
    For $x = 1 to 1000
        If $sPath = -1 Or $sPath = Default Or $sPath == "" Then $sPath = @ScriptDir
        If $sFilter = -1 Or $sFilter = Default Or $sFilter == "" Then $sFilter = "*"
        If Not ($iSearchType == "1") And Not ($iSearchType == "2") Then $iSearchType = "0"
        If Not ($iPathType == "1") And Not ($iPathType == "2") Then $iPathType = "0"
        If $bRecursive = "1" Then
            $bRecursive = True
        Else
            $bRecursive = False
        EndIf
        If $sExclude = -1 Or $sExclude = Default Then $sExclude = ""
        If Not ($iRetFormat == "0") And Not ($iRetFormat == "2") Then $iRetFormat = "1"
    Next
    $t2 = TimerDiff($t2)
    GuiCtrlCreateListViewItem($sPath & "|" & $sFilter & "|" & $iSearchType & "|" & $iPathType & "|" & $bRecursive & "|" & $sExclude & "|" & $iRetFormat, $ListView)

;-------------------------------------------------------------------------------
    While 1
        If GUIGetMsg() = -3 Then ExitLoop
    WEnd
    GUIDelete()
EndFunc

2. If a user were to call this function with values in our 2 "do not use" internal parameters, the results are unpredictable. This is not uncommon in production UDF functions. So, we might as well cut the number of internal parms down to one. Completely removing $bRunFirstTime, and setting the Func default for $sTWorkPath to something like "/*firstcall*/" (a value that will never be passed internally) should do the trick. Then replace the "If $bRunFirstTime Then" statement with:

If $sWorkPath= "/*firstcall*/" Then
    $sWorkPath = ""

3. (I'm nitpicking now) We haven't really abbreviated our other variable names, could we globally change $bRecursiv to $bRecursive ?

4. (Still nitpicking) Would KaFu and Ascend4nt mind if the "Thanks" comment were pulled off the one SRE statement? A *LOT* of people have contributed to this function past and present, and we'd have a list 30-names long to name them all. I don't see those types of comments too often in production.

Edit: These changes will, of course, result in: _FileListToArraySuperTurbo4000PlusProWithMoreUltraPowerboost

Edited by Spiff59
Link to comment
Share on other sites

What a road crossed since the first one post!!!

Very very beautiful work of BaKaMu and Spiff59 and which magnificent function.

I go away this evening 10 days in vacancy (without pc), thus when I would return, I would doubtless see still improvements of your part...

Once again thanks to both.

Best Regards.Thierry

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...