Help in modifying search procedure to run in a Thread

Just starting out? Need help? Post your questions and find answers here.
User avatar
viiartz
User
User
Posts: 70
Joined: Tue Mar 28, 2006 2:00 am

Help in modifying search procedure to run in a Thread

Post by viiartz »

Hi All, Just wanted to ask for help in modifying the below procedure "SearchDirectory()" to run as a thread.

I found the code in the forum (written by collectordave) and I have been using it to search for photo types specified in the RegEx criteria. The code does a good job in finding files except when searching large (2TB etc) hard drives the GUI freezes. The code still run all the way and control is given back to the GUI at the end. I figured if I ran the search in a thread that will not happen hence the help.

Code: Select all

Global NewList FilesFolders.s()
Global SearchFolder.s

Global SearchRegEX.i

#INITIAL_PATH = "c:\"

Procedure SearchDirectory(dir$, List dList.s(), level.l = 0)
  
  Define EntryName.s
  NewList FolderList.s()
  
  Static FileCount.i

  If (level = 0)
    ClearList(dList())
  EndIf
  
  If Right(dir$, 1) <> #PS$
    dir$ + #PS$ 
  EndIf
 
  If ExamineDirectory(0, dir$, "")
    While NextDirectoryEntry(0)
      
      EntryName = DirectoryEntryName(0)     
      
      
      Select DirectoryEntryType(0)
          
        Case #PB_DirectoryEntry_Directory

          If Left(EntryName,1) <> "."  
            AddElement(FolderList())
            FolderList() = EntryName + #PS$
          EndIf

        Case #PB_DirectoryEntry_File

          If Left(EntryName,1) <> "."

            If MatchRegularExpression(SearchRegEx,EntryName)
            
              AddElement(dList())
              FileCount = FileCount + 1
              dList() = dir$ + EntryName     
            
            EndIf
            
          EndIf
        
      EndSelect
  
    Wend
  EndIf

  If ListSize(FolderList())
    ForEach FolderList()
      SearchDirectory(dir$ + FolderList(), dList(), level + 1)
    Next
  EndIf

EndProcedure

Define Word.s

;Search for all image files
 filter.s ="jpg|rw2|cr2|nef|fpx|dcr|pcd|pef|raf|rwl|srw|arw|raw|kdc|iiq|fff|orf|eip|cib|kqp|dng|mrw|mdc|x3f|nop|exf|sr2|crw|ari|3fr|mos|lfr|r3d|mef|nrw|ndd|erf|ra2|dc2|ptx|srf|st7|sd0|sd1|st5|gray|grey|ce2|cmt|craw|st4|st6|gry|nwb|ce1|rwz|3pr|st8|mfw|kc2|olr|cap|stx|dcs|ycbcra|bay|heic|heif"

;Search for .png and .gif only
Word.s = "\.(?i)(" + filter + ")(?-i)$" 
SearchRegEx = CreateRegularExpression(#PB_Any, Word)

;Define the topmost folder to start search
SearchFolder.s = PathRequester("Please choose a SOURCE path", #INITIAL_PATH)

SearchDirectory(SearchFolder, FilesFolders())

ForEach FilesFolders()
  
  Debug FilesFolders()
Next
Thanks,
ViiArtz
infratec
Always Here
Always Here
Posts: 7577
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Help in modifying search procedure to run in a Thread

Post by infratec »

Only short tested:

Code: Select all

CompilerIf Not #PB_Compiler_Thread
  CompilerError "Enable threadsave in compiler options"
CompilerEndIf

EnableExplicit

Enumeration #PB_Event_FirstCustomValue
  #OwnEvent_SearchDirectory_Start
  #OwnEvent_SearchDirectory_FileCount
  #OwnEvent_SearchDirectory_Finished
EndEnumeration



Structure SearchDirectoryParameter_Structure
  Window.i
  Thread.i
  Exit.i
  Level.i
  SearchRegEx.i
  SearchFolder$
  List FileFolderList$()
  FileCount.i
EndStructure



#INITIAL_PATH = "c:\"

Procedure SearchDirectory(*Parameter.SearchDirectoryParameter_Structure)
  
  Protected EntryName$, Dir.i, StartSearchFolder$
  NewList FolderList$()
  
  If *Parameter\Level = 0
    ClearList(*Parameter\FileFolderList$())
  EndIf
  
  If Right(*Parameter\SearchFolder$, 1) <> #PS$
    *Parameter\SearchFolder$ + #PS$ 
  EndIf
  
  Dir = ExamineDirectory(#PB_Any, *Parameter\SearchFolder$, "")
  If Dir
    While NextDirectoryEntry(Dir) And Not *Parameter\Exit
      
      EntryName$ = DirectoryEntryName(Dir)
      
      Select DirectoryEntryType(Dir)
          
        Case #PB_DirectoryEntry_Directory
          
          If Left(EntryName$, 1) <> "."  
            AddElement(FolderList$())
            FolderList$() = EntryName$ + #PS$
          EndIf
          
        Case #PB_DirectoryEntry_File
          
          If Left(EntryName$, 1) <> "."
            
            If MatchRegularExpression(*Parameter\SearchRegEx, EntryName$)
              
              AddElement(*Parameter\FileFolderList$())
              *Parameter\FileCount + 1
              *Parameter\FileFolderList$() = *Parameter\SearchFolder$ + EntryName$
              
              ;PostEvent(#OwnEvent_SearchDirectory_FileCount, *Parameter\Window, 0, 0, *Parameter\FileCount)
              
            EndIf
            
          EndIf
          
      EndSelect
      
    Wend
    FinishDirectory(Dir)
  EndIf
  
  ForEach FolderList$()
    If Not *Parameter\Exit
      StartSearchFolder$ = *Parameter\SearchFolder$
      *Parameter\SearchFolder$ + FolderList$()
      *Parameter\Level + 1
      SearchDirectory(*Parameter)
      *Parameter\SearchFolder$ = StartSearchFolder$
    EndIf
  Next
  
  ;PostEvent(#OwnEvent_SearchDirectory_Finished)
  
EndProcedure



Define Filter$, Word$
Define SearchDirectoryParameter.SearchDirectoryParameter_Structure

;Search for all image files
Filter$ ="jpg|rw2|cr2|nef|fpx|dcr|pcd|pef|raf|rwl|srw|arw|raw|kdc|iiq|fff|orf|eip|cib|kqp|dng|mrw|mdc|x3f|nop|exf|sr2|crw|ari|3fr|mos|lfr|r3d|mef|nrw|ndd|erf|ra2|dc2|ptx|srf|st7|sd0|sd1|st5|gray|grey|ce2|cmt|craw|st4|st6|gry|nwb|ce1|rwz|3pr|st8|mfw|kc2|olr|cap|stx|dcs|ycbcra|bay|heic|heif"

;Search for .png and .gif only
Word$ = "\.(?i)(" + Filter$ + ")(?-i)$" 
SearchDirectoryParameter\SearchRegEx = CreateRegularExpression(#PB_Any, Word$)

;Define the topmost folder to start search
SearchDirectoryParameter\SearchFolder$ = PathRequester("Please choose a SOURCE path", #INITIAL_PATH)
If SearchDirectoryParameter\SearchFolder$
  SearchDirectoryParameter\Thread = CreateThread(@SearchDirectory(), @SearchDirectoryParameter)
  
  WaitThread(SearchDirectoryParameter\Thread)
  
  ForEach SearchDirectoryParameter\FileFolderList$()
    Debug SearchDirectoryParameter\FileFolderList$()
  Next
EndIf
You can also modify it to use child threads instead of recursion.
But that's more tricky.

See also:
viewtopic.php?p=563042
viewtopic.php?p=539371
Oso
Enthusiast
Enthusiast
Posts: 595
Joined: Wed Jul 20, 2022 10:09 am

Re: Help in modifying search procedure to run in a Thread

Post by Oso »

infratec wrote: Sat Jan 21, 2023 10:15 am Only short tested:
I just wanted to say, infratec, that your work converting to a threaded version from Saturday was appreciated by me at least. I particularly liked the idea of passing the thread's id. back into its own structure...

Code: Select all

                           \/
SearchDirectoryParameter\Thread = CreateThread(@SearchDirectory(), @SearchDirectoryParameter)
... I'm just about to use the technique myself, in fact :) Thanks for this.
AZJIO
Addict
Addict
Posts: 2143
Joined: Sun May 14, 2017 1:48 am

Re: Help in modifying search procedure to run in a Thread

Post by AZJIO »

You don't have to use a regular expression. Use SplitL to compare against each element of the list.
Post Reply