Directory recursion

Applications, Games, Tools, User libs and useful stuff coded in PureBasic
User avatar
mk-soft
Always Here
Always Here
Posts: 6245
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Directory recursion

Post by mk-soft »

Who needs it as a thread ...
See Mini Thread Control Example 4

Mentioned only in passing
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
jacdelad
Addict
Addict
Posts: 2010
Joined: Wed Feb 03, 2021 12:46 pm
Location: Riesa

Re: Directory recursion

Post by jacdelad »

Code: Select all

Structure DirStruct
  Directory.s
  List FileList.s()
  SubDirCount.l
EndStructure

Global Dir.DirStruct

Procedure.i RecurseThruDirectories(*directoryStruct.DirStruct)
  Protected NewList TempList.s(),exa,temp$,dir$
  AddElement(TempList())
  TempList()=*directoryStruct\Directory
  If Right(TempList(), 1) <> #PS$
    TempList() = TempList() + #PS$
  EndIf
  *directoryStruct\SubDirCount=0
  ClearList(*directoryStruct\FileList())
  While ListSize(TempList())
    FirstElement(TempList())
    dir$=TempList()
    exa=ExamineDirectory(#PB_Any,dir$,"*.*")
    If exa
      While NextDirectoryEntry(exa)
        temp$=DirectoryEntryName(exa)
        If DirectoryEntryType(exa)=#PB_DirectoryEntry_Directory
          If ReplaceString(temp$,".","")<>""
            *directoryStruct\SubDirCount+1
            AddElement(TempList())
            TempList()=dir$+temp$+#PS$
          EndIf
        Else
          AddElement(*directoryStruct\FileList())
          *directoryStruct\FileList()=dir$+temp$
          Debug dir$+temp$
        EndIf
      Wend
    EndIf
    FirstElement(TempList())
    DeleteElement(TempList())
  Wend
EndProcedure

OpenConsole()
Print("Directory: ")
dir$=Input()
If dir$<>""
  Dir\Directory=dir$
  RecurseThruDirectories(Dir)
  PrintN("Subdirectories: "+Str(Dir\SubDirCount))
  PrintN("Files: "+Str(ListSize(Dir\FileList())))
  PrintN("FileList:")
  ForEach Dir\FileList()
    PrintN(Dir\FileList())
  Next
EndIf
PrintN("Done")
If I didn't make a mistake or failed to understand something about threads, this version should work for threaded and unthreaded usage (aka you can call it as an own thread too).
Good morning, that's a nice tnetennba!

PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
User avatar
RichAlgeni
Addict
Addict
Posts: 935
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: Directory recursion

Post by RichAlgeni »

jacdelad wrote: Tue Feb 21, 2023 9:41 pmBut again, and without trying to be counterproductive, I think this way (including the global variables) is not a good way to do the task.
Then let's see if we can teach you something, shall we? Simple integer addition is atomic. That means the addition is guaranteed to succeed, regardless if the process is threaded or not. What isn't guaranteed, is to know the value of the integer, immediately prior to the addition. This is where we would use atomic functions. Had I intended to present threads, I would have done so. What I did I present, was recursion.
User avatar
idle
Always Here
Always Here
Posts: 5896
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Directory recursion

Post by idle »

I think a depth first traversal of a Directory listing is a good example for teaching recursion or introducing the idea.

you could have used this as a base or reference, perhaps the names not the best for searching
viewtopic.php?p=394408#p394408

You need to add a check if the directory number is valid or it will crash line 44

Code: Select all

directoryNumber = ExamineDirectory(#PB_Any, directoryName, "*.*")  
    If directoryNumber  
       while NextDirectoryEntry(directoryNumber) 
       ;...
       wend 
    Endif 
Did you consider other recursive algorithms like Fibonacci Numbers or Towers of Hanoi (that used to always blow the 1st years minds) If someone doesn't know how recursion works, they're not really going to be able to use it to good effect. Some things are easy to solve with recursion and others not so much.

Code: Select all

Procedure.q Fibonacci_Rec(n.i)
  If (n < 2) 
    ProcedureReturn n 
  Else 
    ProcedureReturn Fibonacci_Rec(n - 1) + Fibonacci_Rec(n - 2)
  EndIf   
EndProcedure    
    
Procedure.q Fibonacci_Iter(n.i)
  Protected vnow.q = 0
  Protected vnext.q = 1 
  Protected vtemp.q 
  
  While n-1 > 0 
      n-1
      vtemp = vnow + vnext
      vnow = vnext       
      vnext = vtemp       
    Wend 
  ProcedureReturn vnext;	
  
EndProcedure    
	
For a = 0 To 20 
	Debug Str(a) + " = " + Str(Fibonacci_Rec(a)) 
	Debug Str(a) + " = " + Str(Fibonacci_Iter(a)) 
Next 


btw I don't think Add mnemonic is atomic, you can make it atomic by adding the Lock prefix or using C intrinsic functions
AZJIO
Addict
Addict
Posts: 2191
Joined: Sun May 14, 2017 1:48 am

Re: Directory recursion

Post by AZJIO »

jacdelad
I doubt it will be fast.

Code: Select all

ReplaceString(temp$,".","")<>""
you will be forced to look for a dot in each file name and replace it with a void, while allocating memory for a new line.

My version was like this, although it also requires a double comparison, but fortunately this comparison will break off at the 1st character

Code: Select all

If name = "." Or name = ".."
	Continue
EndIf
Now I propose a new option, since I learned to check the text by listing the letters. This should run faster as it is done in one pass.

Code: Select all

Define name.s = "..."
*c.Character = @name
If *c\c = '.'
	*c + SizeOf(Character)
	If *c\c = '.'
		*c + SizeOf(Character)
		If *c\c = 0
			Debug ".."
			End
; 			Continue
		EndIf
	ElseIf *c\c = 0
		Debug "."
		End
; 		Continue
	EndIf
EndIf
Debug "yes: " + name
test

Code: Select all

EnableExplicit
DisableDebugger
Define i, StartTime
Define name.s = "."
Define name.s = "dfgdsfgdsfgdsf.dfg"
Define Res.s, Res1.s, Res2.s
Define *c.Character

StartTime = ElapsedMilliseconds()

For i = 1 To 1000000
	*c.Character = @name
	If *c\c = '.'
		*c + SizeOf(Character)
		If *c\c = '.'
			*c + SizeOf(Character)
			If *c\c = 0
				Continue
			EndIf
		ElseIf *c\c = 0
			Continue
		EndIf
	EndIf
Next

Res.s = Str(ElapsedMilliseconds() - StartTime) + " ms"

StartTime = ElapsedMilliseconds()
For i = 1 To 1000000
	If name = "." Or name = ".."
		Continue
	EndIf
Next

Res1.s = Str(ElapsedMilliseconds() - StartTime) + " ms"

StartTime = ElapsedMilliseconds()
For i = 1 To 1000000
	If ReplaceString(name,".","")=""
		Continue
	EndIf
Next

Res2.s = Str(ElapsedMilliseconds() - StartTime) + " ms"

EnableDebugger

Debug Res
Debug Res1
Debug Res2
User avatar
mk-soft
Always Here
Always Here
Posts: 6245
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Directory recursion

Post by mk-soft »

Nonsense,

there's no need to look for any points here.

Directory entry "." is the reference to the current directory and must be ignored.
Directory entry "..." is the reference to the parent directory and must be ignored.

These directory entries are no longer supplied, depending on the system.

Everything else that contains one or more dots are valid directory or file names. The last dot in the file name is the separation to the sufix (file type identifier).
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
AZJIO
Addict
Addict
Posts: 2191
Joined: Sun May 14, 2017 1:48 am

Re: Directory recursion

Post by AZJIO »

mk-soft
What will the first two elements be?
Do we need them in the list we want to get?

Code: Select all

i = 0
id = ExamineDirectory(#PB_Any, "C:\Windows\", "")
If id
	While NextDirectoryEntry(id)
		Debug DirectoryEntryName(id)
		i+1
		If i = 3
			End
		EndIf
	Wend
	FinishDirectory(id)
EndIf
User avatar
mk-soft
Always Here
Always Here
Posts: 6245
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Directory recursion

Post by mk-soft »

These are not used to create lists of directories or files.


They are still needed for relative path specifications. With "../pathname" the parent path is referenced from where the path starts. And on Unix/Linux-based systems, programmes are started in the terminal with "./prg-name" in the current path.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Axolotl
Addict
Addict
Posts: 837
Joined: Wed Dec 31, 2008 3:36 pm

Re: Directory recursion

Post by Axolotl »

mk-soft wrote: Wed Feb 22, 2023 6:34 pm ...
Directory entry "..." is the reference to the parent directory and must be ignored.
...
@mk-soft,
you are right, there is only a little typo -> parent directory is represented by two points ".."
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
Post Reply