Jump to content

Recursive Search / Filename


Recommended Posts

I have searched the help file and the forums up and down but I just can not seem to find a solid answer.

I am looking for a function that will perform a recursive search for a file and retrieve the full file path including the file name.

I need to search for multiple files of the same extension so it would be best if it outputted the full file path and file name to an array.

Any help would be much appreciated.

Thanks.

Link to comment
Share on other sites

  • Moderators

Hi,

This is a recursive search script that I use. I found it on the forums a while ago, but I have no idea of the original author - so credit to who ever it was!.

Might need a bit of tweaking to fit your requirements, but I have found it very reliable.

; Search ("Base folder", "filename");replace as required

Func Search($current,$toFind)
    
If StringRight($current,1) <> "\" then $current &= "\"
    
Local $search_handle = FileFindFirstFile($current & "*.*")

While 1

    $file_found = FileFindNextFile($search_handle)
    
    If @error Or StringLen($file_found) < 1 Then ExitLoop
    
    If StringInStr(FileGetAttrib($current & $file_found), "D") And ($file_found <> "." Or $file_found <> "..") Then
        
; Search this subfolder
        Search($current & $file_found, $toFind) 
        
    Else
        
; Found file
    
    EndIf
WEnd

FileClose($search_handle)

EndFunc

M23

Edited by Melba23

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

Open spoiler to see my UDFs:

Spoiler

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

 

Link to comment
Share on other sites

I have searched the help file and the forums up and down but I just can not seem to find a solid answer.

I am looking for a function that will perform a recursive search for a file and retrieve the full file path including the file name.

I need to search for multiple files of the same extension so it would be best if it outputted the full file path and file name to an array.

Any help would be much appreciated.

Thanks.

Another example.

It appears to be working correctly.

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

Global $sRet 
Local $sPath = @WindowsDir
Local $sFindFile = "calc.exe"

$aRetArray =  _FindPathName($sPath, $sFindFile)
_ArrayDisplay($aRetArray)


; Searches all subfolders of $sPath for $sFindFile (* and ? wildcards accepted)
; Returns an array containing full path and name of all matches.
; Number of matches is in zero index of array
Func _FindPathName($sPath, $sFindFile)
    Local $sSubFolderPath, $iIndex, $aFolders
    $search = FileFindFirstFile($sPath & "\" & $sFindFile)
    $aFolders = _FileListToArray($sPath, "*", 2)
    While 1
        $file = FileFindNextFile($search)
        If @error Then
            ExitLoop
        Else
            $sRet &= $sPath & "\" & $file & "|"
        EndIf
    WEnd
    FileClose($search)
    For $iIndex = 1 To $aFolders[0]
        $sSubFolderPath = $sPath & "\" & $aFolders[$iIndex]
        $aFoldersSubs = _FileListToArray($sSubFolderPath, "*", 2)
        If IsArray($aFoldersSubs) Then _FindPathName($sSubFolderPath, $sFindFile)
    Next
    Return StringSplit(StringTrimRight($sRet,1), "|")
EndFunc  ;==>_FindPathName
Link to comment
Share on other sites

Another example.

It appears to be working correctly.

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

Global $sRet 
Local $sPath = @WindowsDir
Local $sFindFile = "calc.exe"

$aRetArray =  _FindPathName($sPath, $sFindFile)
_ArrayDisplay($aRetArray)


; Searches all subfolders of $sPath for $sFindFile (* and ? wildcards accepted)
; Returns an array containing full path and name of all matches.
; Number of matches is in zero index of array
Func _FindPathName($sPath, $sFindFile)
    Local $sSubFolderPath, $iIndex, $aFolders
    $search = FileFindFirstFile($sPath & "\" & $sFindFile)
    $aFolders = _FileListToArray($sPath, "*", 2)
    While 1
        $file = FileFindNextFile($search)
        If @error Then
            ExitLoop
        Else
            $sRet &= $sPath & "\" & $file & "|"
        EndIf
    WEnd
    FileClose($search)
    For $iIndex = 1 To $aFolders[0]
        $sSubFolderPath = $sPath & "\" & $aFolders[$iIndex]
        $aFoldersSubs = _FileListToArray($sSubFolderPath, "*", 2)
        If IsArray($aFoldersSubs) Then _FindPathName($sSubFolderPath, $sFindFile)
    Next
    Return StringSplit(StringTrimRight($sRet,1), "|")
EndFunc ;==>_FindPathName

Malkey,

I decided to go with your code being that it seemed to be the most strait forward to me... not that the others are bad though.

Anyway, I am very new to AutoIt and my only scripting experience in with Auto Hot Key (I actually thought AutoIt would be similar, but not so much)...

so would you mind explaining exactly what you did here? (especially the string functions which I have a hard time understanding)

I would appreciate it very much!

Link to comment
Share on other sites

Malkey,

I decided to go with your code being that it seemed to be the most strait forward to me... not that the others are bad though.

Anyway, I am very new to AutoIt and my only scripting experience in with Auto Hot Key (I actually thought AutoIt would be similar, but not so much)...

so would you mind explaining exactly what you did here? (especially the string functions which I have a hard time understanding)

I would appreciate it very much!

godsstigma,

FileFindFirstFile(),

FileFindNextFile(), and

FileClose() work together.

And,

_FileListToArray(),

StringSplit(), and

StringTrimRight are all in the help file.

When a matching file is found, the line

$sRet &= $sPath & "\" & $file & "|"

adds to the $sRet string, $sPath & "\" & $file & "|". This line using '&=' is a short-cut way of writing,

$sRet = $sRet & $sPath & "\" & $file & "|".

The "|" is there as a separator of the different matches found. It could be anything. As long as it is will not appear as a character in the found path/file name.

Because, on the Return line in the script, the string is split into an array using this character "|" as a delimiter.

StringSplit(StringTrimRight($sRet,1), "|")

But before the string is split, the last "|" of the $sRet string needs to be deleted. If not deleted, the StringSplit() will also split on the last "|" at the end of the string, $sRet, returning an array with a false blank array element at the end.

The StringTrimRight() function used, removes one character from the right of the string, $sRet, which is, and will be "|".

Hope this helps.

Malkey

Link to comment
Share on other sites

  • 3 weeks later...

Hi, I wrote this function for search files from a top folder specified as input value.

My main objective was to have a simple function that I can include in other codes, when I need to search or locate files in a tree.

I had located other codes, but those are ones that I need to embed my target operation INSIDE the search code.

Let me explain this:

Fucntion SearchFile (File_to find)
   (Begin  search engine)
    ; ----- Target Operation: 
          If file searched found, then do whatever you want
   (End of search Engine)
EndFunction

In other words, I need to modify the search function for every application that need search for a file.

My point is that I don´t want to touch a function that I had already tested and is working properly. I need a simple call to a function to search a file, do whatever I want with that file, and close the search whenever I need.

For example:

Function My_Taget_Function (My_Input Values)
   Some code
   (...)
  ; Then I need to search file(s) !!!
   $NotFound=True
   While $NotFound
      $File=ScanFolder(C:\Documents and Settings)
         If This is my file then
            Do whatever I want with the file
           ; And then stop search when done:
            ScanFolder (-ABORT-)
         EndIf
   Wend
   (...)
EndFunction

This is my code. I hope result useful for anyone. Greetings!

;----------------------------------------------------------------------------------------------------
;   Scan Folder Function
;
;   This Function scans files in the folder specified and sub folders tree (if any)
;   The first time it´s invoked CREATES a Search and returns the FULL PATH of the File found
;   Subsecuents calls, continues the search until no more files are found and closes de search
;   When end of search is reached, RETURNS -1 instead of the file name.
;
;   If the caller wants to cancel/stop/abort the search, calls the function with the Keyword "-ABORT-"
;   as Source Folder.
;
;   Input: 
;     Start Folder to Scan or "-ABORT-" 
;   Returns: 
;     Full path to file found or -1
;----------------------------------------------------------------------------------------------------

#include-once 

#Include <Array.au3>

; Field Definition
Enum $_FLD_SourceFolder, $_FLD_SearchHandle, $_FLD_File, $_FLD_FullFilePath, $_FLD_FileAttributes, $_FLD_SearchStat, $_FLD_RecursionLevel, $_Dim
Const $Stack_Deep = $_Dim * 256

; Work Arrays for the Function 
    DIM $SD [$_Dim]
    DIM $Stack [$Stack_Deep]
    Dim $Stack_Pointer = $Stack_Deep - 1

; Default Values
    $SD [$_FLD_SourceFolder] = "NONE"
    $SD [$_FLD_SearchHandle] = 0
    $SD [$_FLD_File] = "NONE"
    $SD [$_FLD_FullFilePath] = "NONE"
    $SD [$_FLD_FileAttributes] = "NONE"
    $SD [$_FLD_SearchStat] = "INIT"
    $SD [$_FLD_RecursionLevel] = 0

Func PushDTA ()
    Local $i
    For $i = 0 to ($_Dim - 1)
        $Stack [$Stack_Pointer] = $SD [$i]
        $Stack_Pointer -= 1
    Next
    
    $SD [$_FLD_RecursionLevel] += 1
EndFunc

Func PopDTA ()
    Local $i
    For $i = ($_Dim - 1) to 0 Step -1
        $Stack_Pointer += 1
        $SD[$i] = $Stack[$Stack_Pointer]
    Next
EndFunc


Func ScanFolder($SourceFolder)
    Local $RetVal = ""
    
    If $SourceFolder == "-ABORT-" Then
        Switch $SD [$_FLD_SearchStat]
            Case "INIT"
                $RetVal = -1    ; Nothing Done - Return
                
            Case "FIND_FIRST"
                $SD [$_FLD_SearchStat] = "ABORT"
                
            Case "FIND_NEXT"
                $SD [$_FLD_SearchStat] = "ABORT"
                
            Case Else
                MsgBox(48,"ERROR","Unknown Internal Search State. ABORTED!")
                $RetVal = -1
        EndSwitch
        
    EndIf
    
    While $RetVal = ""
        Switch $SD [$_FLD_SearchStat]
            Case "INIT"
            ; Init Search Array
                If StringRight($SourceFolder,1) == "\" Then
                    $SourceFolder = StringLeft($SourceFolder,StringLen($SourceFolder)-1)
                EndIf
                $SD [$_FLD_SourceFolder] = $SourceFolder
                $SD [$_FLD_SearchHandle] = 0
                $SD [$_FLD_File] = "NONE"
                $SD [$_FLD_FullFilePath] = "NONE"
                $SD [$_FLD_FileAttributes] = "NONE"
                $SD [$_FLD_SearchStat] = "FIND_FIRST"; Next Phase
                $SD [$_FLD_RecursionLevel] = 0
           
            Case "FIND_FIRST"
                $SD [$_FLD_SearchHandle] = FileFindFirstFile($SD [$_FLD_SourceFolder] & "\*.*")
                If $SD [$_FLD_SearchHandle] = -1 Then
                    If $SD [$_FLD_RecursionLevel] < 1 Then   ; Top Level ?
                        $SD [$_FLD_SearchStat] = "INIT"     ; Next Phase Start. Work Done.
                        $RetVal = -1                           ; End Execution and Retval NoMoreFiles
                    Else
                        PopDTA()                            ; Not in Top Level, Continue.
                    EndIf
                Else
                   $SD [$_FLD_SearchStat] = "FIND_NEXT"      ; OK, Find Next File.              
                EndIf

            Case "FIND_NEXT"
                $SD [$_FLD_File] = FileFindNextFile($SD [$_FLD_SearchHandle])
                    IF @error Then
                        If $SD [$_FLD_RecursionLevel] < 1 Then   ; Top Level ?
                            $SD [$_FLD_SearchStat] = "INIT"     ; Next Phase Start. Work Done.
                            $RetVal = -1                           ; End Execution and Retval NoMoreFiles
                            FileClose($SD [$_FLD_SearchHandle])
                        Else
                            FileClose($SD [$_FLD_SearchHandle]) ; No More Files in current Level. Close current Search 
                            PopDTA()                            ; Continue in upper level.
                        EndIf
                    Else
                        $SD [$_FLD_FullFilePath] = $SD [$_FLD_SourceFolder]  & "\" & $SD [$_FLD_File] ;   $FullFilePath = $SourceFolder & "\" & $ File
                        $SD [$_FLD_FileAttributes] = FileGetAttrib($SD [$_FLD_FullFilePath])        ;   $FileAttributes = FileGetAttrib($FullFilePath)
                            If StringInStr($SD [$_FLD_FileAttributes],"D") Then                         ;   If StringInStr($FileAttributes,"D") Then
                                PushDTA()                                                               ;   If Directory, Save Data and start recursion
                                $SD [$_FLD_SourceFolder] = $SD [$_FLD_FullFilePath]
                                $SD [$_FLD_SearchStat] = "FIND_FIRST"                               ;   Next Phase: Find First starting from here
                            Else                                                                ;   Normal File To Report
                                $RetVal = $SD [$_FLD_FullFilePath]      ; Exit Procedure Returning File Found
                            EndIf
                    EndIf
                        
                Case "ABORT"
                    While $SD [$_FLD_RecursionLevel] > 0
                        FileClose($SD [$_FLD_SearchHandle])
                        PopDTA()
                    WEnd
                    If $SD [$_FLD_SearchHandle] > -1 Then
                        FileClose($SD [$_FLD_SearchHandle])
                    EndIf
                    $SD [$_FLD_SearchStat] = "INIT"     ; Next Phase Start. Work Done.
                    $RetVal = -1

            Case Else
                MsgBox(48,"ERROR","Unknown Internal Search State. ABORTED!")
                $RetVal = -1
                
        EndSwitch
    WEnd
           
    Return $RetVal
EndFunc     

; --------------------------------------------------------
;
; MAIN - TESTING
;
; --------------------------------------------------------


$File=""
$Count=0
While $File > -1
    $File = ScanFolder("C:\")
    ToolTip($File,0,200)
    FileWriteLine(@ScriptDir & "\ScanFolder.txt" ,$File)
    $Count += 1
    If $Count >= 2000 Then
       $File = ScanFolder("-ABORT-")
    EndIf
WEnd

MsgBox(0,"Scan Completed","Files Found: " & $Count)

Funct_ScanFolder.au3

Link to comment
Share on other sites

  • 2 months later...

Hello Saruman,

thanks for this source code, but I have a question. How can I modify this code to search one file (example : system.exe) in a patch c:\?

I want already have the properties of the file(s), size, version, date,... Could you help me?

Thanks in advance, Regards

Edited by ricky03
Link to comment
Share on other sites

  • 1 month later...

Hello Saruman,

thanks for this source code, but I have a question. How can I modify this code to search one file (example : system.exe) in a patch c:\?

I want already have the properties of the file(s), size, version, date,... Could you help me?

Thanks in advance, Regards

Hello ricky03. First of all, sorry for the delayed reply, but I´m was off-line for some time.

I think that you do not need to modify the search code. In your main code you can filter the result what you want.

For example:

$File=""
$Version=""
$Size=""
$FileDate=""

While $File > -1
    $File = ScanFolder("C:\")
    If StringInstr($File, "system.exe") Then
        $Version=FileGetVersion($File, "FileVersion")
        $Size=FileGetSize ($File)
        $FileDate=FileGetTime ( $File,1,1)
    ; ETC.....
        FileWriteLine(@ScriptDir & "\ScanFolder.csv" ,$File & "," & $Version & "," & $Size & "," & $FileDate)
    EndIf

    ToolTip($File,0,200)
 
WEnd

I hope this can help you. Regards!

Edited by Saruman
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...