destro Posted October 12, 2009 Share Posted October 12, 2009 (edited) Hi all, I've been trying to get my head round Functions and decided to try to modify some code to do some recursive folder searching for a particular file. The code takes a file to search for and a root directory and searches for the file and returns the full path. Here's the code: expandcollapse popupDim $SearchFile = "bod_r.TTF" Dim $StartDir = @ProgramFilesDir Dim $SearchResult = 0 $FilePath = FileSearch($SearchFile, $StartDir) MsgBox(0,"FilePath",$FilePath) Exit Func FileSearch($SearchFile, $StartDir, $Depth = 0) If $Depth = 0 Then Global $RFString = "" $Search = FileFindFirstFile($StartDir & "\*.*") If @error Then Return ;Search through all files and folders in directory While $SearchResult = 0 $Next = FileFindNextFile($Search) If @error Then ExitLoop ;If folder, recurse If StringInStr(FileGetAttrib($StartDir & "\" & $Next), "D") Then FileSearch($SearchFile, $StartDir & "\" & $Next, $Depth + 1) Else ;Append filename to master string $RFString = $StartDir & "\" & $Next EndIf If $Next = $SearchFile Then $SearchResult = 1 EndIf WEnd FileClose($Search) If $SearchResult = 1 Then Return $RFString Else Return "File Not Found" EndIf EndFunc ;==>FileSearch The problem is that I can't seem to work out a way to use the function without declaring the $SearchResult = 0 first. This is annoying as it means the Function is not self contained. The $SearchResult is used to keep the While loop alive and also to determine what is returned. If I Dim it inside the fuction then it breaks it (Returns File Not Found). Any more experinced people got any idea how I can make this work so it's self contained so i can start to build my own #include file. Thanks Edited October 12, 2009 by destro Link to comment Share on other sites More sharing options...
TurionAltec Posted October 12, 2009 Share Posted October 12, 2009 (edited) If you declare it as a global variable inside the function: Global $SearchResult = 0 Then it seems to work. I haven't go the foggiest idea why it doesn't work as a local variable. To recursively find a file, I'd tend to use (Dir /s/B ) Edited October 12, 2009 by TurionAltec Link to comment Share on other sites More sharing options...
martin Posted October 12, 2009 Share Posted October 12, 2009 (edited) Hi all, I've been trying to get my head round Functions and decided to try to modify some code to do some recursive folder searching for a particular file. The code takes a file to search for and a root directory and searches for the file and returns the full path. Here's the code: expandcollapse popupDim $SearchFile = "bod_r.TTF" Dim $StartDir = @ProgramFilesDir Dim $SearchResult = 0 $FilePath = FileSearch($SearchFile, $StartDir) MsgBox(0,"FilePath",$FilePath) Exit Func FileSearch($SearchFile, $StartDir, $Depth = 0) If $Depth = 0 Then Global $RFString = "" $Search = FileFindFirstFile($StartDir & "\*.*") If @error Then Return ;Search through all files and folders in directory While $SearchResult = 0 $Next = FileFindNextFile($Search) If @error Then ExitLoop ;If folder, recurse If StringInStr(FileGetAttrib($StartDir & "\" & $Next), "D") Then FileSearch($SearchFile, $StartDir & "\" & $Next, $Depth + 1) Else ;Append filename to master string $RFString = $StartDir & "\" & $Next EndIf If $Next = $SearchFile Then $SearchResult = 1 EndIf WEnd FileClose($Search) If $SearchResult = 1 Then Return $RFString Else Return "File Not Found" EndIf EndFunc ;==>FileSearch The problem is that I can't seem to work out a way to use the function without declaring the $SearchResult = 0 first. This is annoying as it means the Function is not self contained. The $SearchResult is used to keep the While loop alive and also to determine what is returned. If I Dim it inside the fuction then it breaks it (Returns File Not Found). Any more experinced people got any idea how I can make this work so it's self contained so i can start to build my own #include file. Thanks I haven't tested this but it might work. Dim $SearchFile = "bod_r.TTF" Dim $StartDir = @ProgramFilesDir ;Dim $SearchResult = 0 $FilePath = FileSearch($SearchFile, $StartDir) MsgBox(0, "FilePath", $FilePath) Exit Func FileSearch($SearchFile, $StartDir);, $Depth = 0) ;If $Depth = 0 Then Global Local $Search, $RFString = "File not found" $Search = FileFindFirstFile($StartDir & "\*.*") If @error Then Return $RFString ;Search through all files and folders in directory While $Refstring = "File not found" $Next = FileFindNextFile($Search) If @error Then ExitLoop ;If folder, recurse If StringInStr(FileGetAttrib($StartDir & "\" & $Next), "D") Then $RFString = FileSearch($SearchFile, $StartDir & "\" & $Next);, $Depth + 1) Else if $Next = $SearchFile then $RFString = $StartDir EndIf WEnd FileClose($Search) Return $RFString EndFunc ;==>FileSearch You can also pass variables by reference so that avoids needing a global variable inside your function. You could also have the function return an array, so you could make one element the file path, another element some other value. EDIT:Corrected return in one place. Edited October 12, 2009 by martin Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script. Link to comment Share on other sites More sharing options...
zodiac Posted October 13, 2009 Share Posted October 13, 2009 I use this and it works great: #include<file.au3> _search("C:\") Func _search($dir) Local $ArrTargetItems, $TargetItem If (StringRight($dir, 1) = "\") Then $dir = StringTrimRight($dir, 1) $ArrTargetItems = _FileListToArray($dir, "*", 0) If IsArray($ArrTargetItems) Then For $n = 1 To $ArrTargetItems[0] $TargetItem = $dir & '\' & $ArrTargetItems[$n] If StringInStr(FileGetAttrib($TargetItem), "D") Then ;This is a folder _search($TargetItem) ;Call recursively Else ;This is a file ;Do whatever you want to do with the file here. ;$TargetItem contains the file full path ;$ArrTargetItems[$n] contains the file name MsgBox(0, $ArrTargetItems[$n], $TargetItem) EndIf Next EndIf EndFunc ;==>_search Tested on volumes with 2 Terabytes and didn't skip a beat. Link to comment Share on other sites More sharing options...
destro Posted October 13, 2009 Author Share Posted October 13, 2009 Thanks very much to all who came up with ideas for this. I've kinda scrapped my original function although it was very useful as a learning exercise (my first one!) as Zodiac provided a very elegant solution to the problem. Next on the list, recursive registry searching... Link to comment Share on other sites More sharing options...
ironmankho Posted October 13, 2009 Share Posted October 13, 2009 Your code is awesome ..... it is possible it search only specific extension on c: drive like *.xls Link to comment Share on other sites More sharing options...
destro Posted October 13, 2009 Author Share Posted October 13, 2009 Ok guys, I actually went back to my original code as Zodiac's script wasn't giving me quite what I wanted (I couldn't seem to Return the value out of the function that I was after). I took on board the comments that you guys suggested and came up with the following code Dim $SearchFile = "iexplore.exe" Dim $StartDir = @ProgramFilesDir $FilePath = FileSearch($SearchFile, $StartDir) MsgBox(0, "FilePath", $FilePath) Exit Func FileSearch($SearchFile, $StartDir) Local $Search, $RFString = "File not found" $Search = FileFindFirstFile($StartDir & "\*.*") If @error Then Return $RFString ;Search through all files and folders in directory While $RFString = "File not found" $Next = FileFindNextFile($Search) If @error Then ExitLoop ;If folder, recurse If StringInStr(FileGetAttrib($StartDir & "\" & $Next), "D") Then $RFString = FileSearch($SearchFile, $StartDir & "\" & $Next) Else If $Next = $SearchFile Then $RFString = $StartDir & "\" & $Next EndIf WEnd FileClose($Search) Return $RFString EndFunc ;==>FileSearch This works a treat and gives me exactly what I was after. Thanks again all Link to comment Share on other sites More sharing options...
ironmankho Posted October 15, 2009 Share Posted October 15, 2009 can it is possible it search all hard drive partition ? to specific extension file like *.doc How ? Link to comment Share on other sites More sharing options...
omikron48 Posted October 15, 2009 Share Posted October 15, 2009 (edited) I made a search function some time ago using a stack. You need to control the size of the predeclared arrays if you want to trim down on the memory usage. expandcollapse popup;Put somewhere at the start of your script ;### STACK DEFINITION ### Global $RESULT_MAX = 0xFFF ;maximum size of the returned array Global $STACK_MAX = 0xFFF ;maximum size of the search stack Global $STACK[$STACK_MAX] ;the search stack $STACK[0] = 0 ;stack element counter Func _Push($var) ;Utility function. DO NOT CALL If $STACK[0] < $STACK_MAX - 1 Then $STACK[0] += 1 $STACK[$STACK[0]] = $var Else Return 1 EndIf Return 0 EndFunc Func _Pop() ;Utility function. DO NOT CALL If $STACK[0] > 0 Then $STACK[0] -= 1 Return $STACK[$STACK[0] + 1] Else SetError(1) EndIf Return 0 EndFunc ;### END STACK DEFINITION ### ;### SEARCH FUNCTION ### ;$path = start location of search ;$filter = expression to use for file matching (e.g. *.txt) ;$exclude = file attributes to exclude from search (e.g. if you want to skip system and/or hidden folders) ;$depth = folder depth to limit search ; 0 -> current folder only ; n -> search up to n folders deep ; -1 -> search in all subfolders ; ;Returns array containing full path of matched files, with [0] containing the count of returned elements. Func _Search($path, $filter, $exclude, $depth) Local $current = @WorkingDir If FileChangeDir($path) == 1 Then If StringCompare(StringRight($path, 1), "\") <> 0 Then $path &= "\" EndIf Local $array[2] = [$path, 0] _Push($array) Local $result = _SearchUtil($filter, $exclude, $depth) FileChangeDir($current) Return $result Else SetError(1) EndIf FileChangeDir($current) Local $empty[2] = [0, 0] Return $empty EndFunc Func _SearchUtil($filter, $exclude, $depth) ;Utility function. DO NOT CALL Local $result[$RESULT_MAX] Local $search, $fname, $attrib Local $array[2], $temp[2] $result[0] = 0 While 1 ;get top of stack $array = _Pop() If @error == 1 Then ExitLoop EndIf ;change directory FileChangeDir($array[0]) ;search for matches in current directory $search = FileFindFirstFile($filter) While 1 $fname = FileFindNextFile($search) If @error == 1 Then ExitLoop EndIf $attrib = FileGetAttrib($fname) If _IsIncluded($attrib, $exclude) Then $result[0] += 1 $result[$result[0]] = $array[0] & $fname EndIf WEnd ;search subdirectory If $depth == -1 Or $array[1] < $depth Then $search = FileFindFirstFile("*") While 1 $fname = FileFindNextFile($search) If @error == 1 Then ExitLoop EndIf $attrib = FileGetAttrib($fname) If StringInStr($attrib, "D") <> 0 Then If _IsIncluded($attrib, $exclude) Then $temp[0] = $array[0] & $fname & "\" $temp[1] = $array[1] + 1 _Push($temp) EndIf EndIf WEnd EndIf WEnd Return $result EndFunc Func _IsIncluded($attrib, $exclude) ;Utility function. DO NOT CALL For $i = 1 To StringLen($exclude) If StringInStr($attrib, StringMid($exclude, $i, 1)) <> 0 Then Return False EndIf Next Return True EndFunc ;### END SEARCH FUNCTION ### Edited October 15, 2009 by omikron48 Link to comment Share on other sites More sharing options...
PeterAtkin Posted February 23, 2010 Share Posted February 23, 2010 (edited) @omikron48 this looks like just what I have been looking for but how do you use this as I tried various ways such as _Search("c:\", "*.rnd","a",0), or _Search("c:\", "autorun.*","",-1) and several other but I get no results even when I use a file i know is there.. also it not clear how one would use the exclude option.. Hope I am making sence.. Edited February 23, 2010 by PeterAtkin [topic='115020'] AD Domain Logon Script[/topic] Link to comment Share on other sites More sharing options...
omikron48 Posted February 23, 2010 Share Posted February 23, 2010 (edited) The exclude parameter is used for filtering search and search results. If a file property value is included in the exclude string, the file is skipped. If a subdirectory property value is included in the exclude string, the subdirectory and its contents are are skipped from the search. e.g. If the exclude string is "SH", the search will skip files and subdirectory branches that have either system or hidden set. _Search("c:\", "*.rnd","a",0) This will not return anything unless you do backups which clear the archive bit from your files and folders. _Search("c:\", "autorun.*","",-1) This should be fine if any file fits the "autorun.*" filter. I just tested my code again with a folder setup like so: C:\test\autorun.bat C:\test\autorun.txt C:\test\test.bat C:\test\test.txt C:\test\autorun\autorun.file C:\test\autorun\test.file C:\test\test\autorun.zip C:\test\test\test.zip This is the script I used for testing: expandcollapse popupOpt("MustDeclareVars", 1) ;Put somewhere at the start of your script ;### STACK DEFINITION ### Global $RESULT_MAX = 0xFFF ;maximum size of the returned array Global $STACK_MAX = 0xFFF ;maximum size of the search stack Global $STACK[$STACK_MAX] ;the search stack $STACK[0] = 0 ;stack element counter Func _Push($var) ;Utility function. DO NOT CALL If $STACK[0] < $STACK_MAX - 1 Then $STACK[0] += 1 $STACK[$STACK[0]] = $var Else Return 1 EndIf Return 0 EndFunc Func _Pop() ;Utility function. DO NOT CALL If $STACK[0] > 0 Then $STACK[0] -= 1 Return $STACK[$STACK[0] + 1] Else SetError(1) EndIf Return 0 EndFunc ;### END STACK DEFINITION ### ;### TEST SCRIPT ### Global $array = _Search("c:\test", "autorun.*","",-1) Global $display = "" For $i = 1 To $array[0] $display &= $array[$i] & @CRLF Next MsgBox(0x2000, "Search Results: " & $array[0], $display) ;### TEST SCRIPT ### ;### SEARCH FUNCTION ### ;$path = start location of search ;$filter = expression to use for file matching (e.g. *.txt) ;$exclude = file attributes to exclude from search (e.g. if you want to skip system and/or hidden folders) ;$depth = folder depth to limit search ; 0 -> current folder only ; n -> search up to n folders deep ; -1 -> search in all subfolders ; ;Returns array containing full path of matched files, with [0] containing the count of returned elements. Func _Search($path, $filter, $exclude, $depth) Local $current = @WorkingDir If FileChangeDir($path) == 1 Then If StringCompare(StringRight($path, 1), "\") <> 0 Then $path &= "\" EndIf Local $array[2] = [$path, 0] _Push($array) Local $result = _SearchUtil($filter, $exclude, $depth) FileChangeDir($current) Return $result Else SetError(1) EndIf FileChangeDir($current) Local $empty[2] = [0, 0] Return $empty EndFunc Func _SearchUtil($filter, $exclude, $depth) ;Utility function. DO NOT CALL Local $result[$RESULT_MAX] Local $search, $fname, $attrib Local $array[2], $temp[2] $result[0] = 0 While 1 ;get top of stack $array = _Pop() If @error == 1 Then ExitLoop EndIf ;change directory FileChangeDir($array[0]) ;search for matches in current directory $search = FileFindFirstFile($filter) While 1 $fname = FileFindNextFile($search) If @error == 1 Then ExitLoop EndIf $attrib = FileGetAttrib($fname) If _IsIncluded($attrib, $exclude) Then $result[0] += 1 $result[$result[0]] = $array[0] & $fname EndIf WEnd ;search subdirectory If $depth == -1 Or $array[1] < $depth Then $search = FileFindFirstFile("*") While 1 $fname = FileFindNextFile($search) If @error == 1 Then ExitLoop EndIf $attrib = FileGetAttrib($fname) If StringInStr($attrib, "D") <> 0 Then If _IsIncluded($attrib, $exclude) Then $temp[0] = $array[0] & $fname & "\" $temp[1] = $array[1] + 1 _Push($temp) EndIf EndIf WEnd EndIf WEnd Return $result EndFunc Func _IsIncluded($attrib, $exclude) ;Utility function. DO NOT CALL For $i = 1 To StringLen($exclude) If StringInStr($attrib, StringMid($exclude, $i, 1)) <> 0 Then Return False EndIf Next Return True EndFunc ;### END SEARCH FUNCTION ### I got correct results. Thinking about it, some more improvements could be done on the search code: Separating the $exclude filter for match results and subdirectory searches, so you can search for hidden files while skipping looking into system folders. Adding an option to select whether folders are returned with match results or not. Edited February 23, 2010 by omikron48 Link to comment Share on other sites More sharing options...
PeterAtkin Posted February 24, 2010 Share Posted February 24, 2010 Thanks that was a great help, and yes I agree this could benefit from the additions you have mentioned. [topic='115020'] AD Domain Logon Script[/topic] Link to comment Share on other sites More sharing options...
omikron48 Posted February 24, 2010 Share Posted February 24, 2010 I already did some improvements to the code. Found here.One uses regular expressions for matching, the other uses FileFindFirstFile's matching method. Link to comment Share on other sites More sharing options...
dirty Posted March 4, 2010 Share Posted March 4, 2010 (edited) is that what you were looking for ? #Include <File.au3> $dir = (C:\) ;where to search at Func _search($dir) DirCreate ($UT3ResultPath) Local $ArrTargetItems, $TargetItem If (StringRight($dir, 1) = "\") Then $dir = StringTrimRight($dir, 1) $ArrTargetItems = _FileListToArray($dir, "*", 0) If IsArray($ArrTargetItems) Then For $n = 1 To $ArrTargetItems[0] $TargetItem = $dir & '\' & $ArrTargetItems[$n] If StringInStr(FileGetAttrib($TargetItem), "D") Then ;This is a folder _search($TargetItem) ;Call recursively. in other words search for more Else ;This is a file $getext = StringRight ($TargetItem,4) ;get last 4 of file name If $getext = ".uz3" Then ;if file extansion matches to Endif EndIf Next EndIf EndFunc Edited March 4, 2010 by dirty Link to comment Share on other sites More sharing options...
UEZ Posted March 4, 2010 Share Posted March 4, 2010 I wrote also a function to search for files -> Seek for FilesMaybe it is helpful, too.UEZ Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ Link to comment Share on other sites More sharing options...
kiepcamca Posted February 19, 2013 Share Posted February 19, 2013 I use this and it works great: #include<file.au3> _search("C:\") Func _search($dir) Local $ArrTargetItems, $TargetItem If (StringRight($dir, 1) = "\") Then $dir = StringTrimRight($dir, 1) $ArrTargetItems = _FileListToArray($dir, "*", 0) If IsArray($ArrTargetItems) Then For $n = 1 To $ArrTargetItems[0] $TargetItem = $dir & '\' & $ArrTargetItems[$n] If StringInStr(FileGetAttrib($TargetItem), "D") Then ;This is a folder _search($TargetItem) ;Call recursively Else ;This is a file ;Do whatever you want to do with the file here. ;$TargetItem contains the file full path ;$ArrTargetItems[$n] contains the file name MsgBox(0, $ArrTargetItems[$n], $TargetItem) EndIf Next EndIf EndFunc ;==>_search Tested on volumes with 2 Terabytes and didn't skip a beat. Oh, thank you very much. It very great.^^ Link to comment Share on other sites More sharing options...
AZJIO Posted February 19, 2013 Share Posted February 19, 2013 (edited) kiepcamca Edited February 19, 2013 by AZJIO My other projects or all Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now