EnableExplicit
#systemSlash = "\"
Define directoryName.s
Define NewList fileListName.s()
Define startTime.i
Define completeTime.i
Global directoryCount.i
Global fileCount.i
OpenConsole()
CompilerIf #PB_Compiler_Thread = 1
CompilerError "This program is NOT thread safe"
CompilerEndIf
PrintN("This process will count the number of subdirectories and files in a diretory")
PrintN("")
PrintN("It will add the complete file name for each file found to a list")
PrintN("")
Print("Enter the directory name you wish to start with: ")
directoryName = Input()
Procedure.i RecurseThruDirectories(*directoryName, List fileListName.s())
Protected fileName.s
Protected newDirectory.s
Protected directoryName.s
Protected directoryNumber.i
; make sure our directory name ends with a system slash
directoryName = PeekS(*directoryName)
If Right(directoryName, 1) <> #systemSlash
directoryName = directoryName + #systemSlash
EndIf
PrintN(directoryName)
directoryCount + 1
; loop thru the entries in a directory
directoryNumber = ExamineDirectory(#PB_Any, directoryName, "*.*")
While NextDirectoryEntry(directoryNumber)
If DirectoryEntryType(directoryNumber) = #PB_DirectoryEntry_File
fileName = directoryName + DirectoryEntryName(directoryNumber)
AddElement(fileListName())
fileListName() = fileName
fileCount + 1
Else
newDirectory = DirectoryEntryName(directoryNumber)
Select newDirectory
Case "."
Case ".."
Default
newDirectory = directoryName + newDirectory
RecurseThruDirectories(@newDirectory, fileListName())
EndSelect
EndIf
Wend
FinishDirectory(directoryNumber)
EndProcedure
startTime = ElapsedMilliseconds()
RecurseThruDirectories(@directoryName, fileListName())
completeTime = ElapsedMilliseconds()
PrintN("")
PrintN("There were "+ Str(directoryCount) + " directories found")
PrintN("")
PrintN("There were "+ Str(fileCount) + " files found")
PrintN("")
PrintN("There are "+ Str(ListSize(fileListName())) + " files in the list")
PrintN("")
PrintN("This process took " + Str(completeTime - startTime) + " milliseconds to complete")
PrintN("")
Print("Press <enter> to end: ")
Input()
CloseConsole()
End
Why do I need to use the threadsafe-option if you're not using threads?
Also I think it's better to use a non-recursive variant. But we had this discussion here before.
PureBasic 6.04/XProfan X4a/Embarcadero RAD Studio 11/Perl 5.2/Python 3.10
Windows 11/Ryzen 5800X/32GB RAM/Radeon 7770 OC/3TB SSD/11TB HDD
Synology DS1821+/36GB RAM/130TB
Synology DS920+/20GB RAM/54TB
Synology DS916+ii/8GB RAM/12TB
I'm sorry if this sounds rude now, but:
- don't put threadsafe in when threadsafe is not needed
- the program crashes with something like "directory not initialized" (I'm using the german version) when searching through "C:\Windows\System32", because you don't check if ExamineDirectory(...) returns success or not
- I don't see the point in using a recursive algorithm for that
- using the address instead of the string itself seems counterproductive
Again, I'm open for a conversation.
Last edited by jacdelad on Mon Feb 20, 2023 11:42 pm, edited 1 time in total.
PureBasic 6.04/XProfan X4a/Embarcadero RAD Studio 11/Perl 5.2/Python 3.10
Windows 11/Ryzen 5800X/32GB RAM/Radeon 7770 OC/3TB SSD/11TB HDD
Synology DS1821+/36GB RAM/130TB
Synology DS920+/20GB RAM/54TB
Synology DS916+ii/8GB RAM/12TB
I'm not sure why it is so difficult for you to actually read the code I posted. The CompilerIf statement will throw an error if you try to compile the code with the option 'Create threadsafe executable' checked, therefore it does not use threads. As far as having a conversation, I'm also not sure how, given your erroneous interpretation of this small routine, I would benefit.
RichAlgeni wrote: ↑Tue Feb 21, 2023 12:43 am
I'm not sure why it is so difficult for you to actually read the code I posted. The CompilerIf statement will throw an error if you try to compile the code with the option 'Create threadsafe executable' checked, therefore it does not use threads. As far as having a conversation, I'm also not sure how, given your erroneous interpretation of this small routine, I would benefit.
Yes, you're right. I misinterpreted that. But why do you disallow running it when threadsafe is enabled? This doesn't make sense, too.
PureBasic 6.04/XProfan X4a/Embarcadero RAD Studio 11/Perl 5.2/Python 3.10
Windows 11/Ryzen 5800X/32GB RAM/Radeon 7770 OC/3TB SSD/11TB HDD
Synology DS1821+/36GB RAM/130TB
Synology DS920+/20GB RAM/54TB
Synology DS916+ii/8GB RAM/12TB
@RichAlgeni: Thanks for providing some example code for individuals pondering recursion. The forum could always use more code examples and tutorials.
I have a small remark about your code and the use of a string pointer. In your code for procedure RecurseThruDirectories() you pass a pointer *directoryName. I presume you pass a pointer instead of a string so that you can avoid an unnecessary copy of the directoryName string.
However, in the procedure the first thing that is done is an immediate read of the string using the pointer and you store another copy of it. When recursing back into the procedure you pass a pointer to this new copy of the string and everything starts all over again. IMHO, this makes using a pointer to the directoryName instead of the actual string pointless (pun intended).
@jacdelad:
The code posted by RichAlgeni is not threadsafe because he is using global counter variables inside RecurseThruDirectories().
Therefore you cannot use RecurseThruDirectories() in threads without intermixing these counts.
Here you can replace Global by Threaded.
However, directoryCount and fileCount are even not reseted, so the code is only working as it is.
Demivec wrote: ↑Tue Feb 21, 2023 3:50 amI have a small remark about your code and the use of a string pointer. In your code for procedure RecurseThruDirectories() you pass a pointer *directoryName. I presume you pass a pointer instead of a string so that you can avoid an unnecessary copy of the directoryName string.
I have never liked passing strings, I always pass pointers. Then, I used PeekS() as ExamineDirectory() does not take a pointer.
@kiffi: Yes, I know about the system delimiters, but since this was an example of recursion, I deemed it not a big deal.
@jacdelad: Recursion by its nature is not threaded, as a procedure is calling a new instance of itself. The purpose of this example wasn't to extoll the virtue of non-threaded code, it was simply an example of recursion for those who might be interested.
Use the s.String structure, then you will have both a string and a pointer without having to use PeekS.
When you call a new function, you leave the previous function open, so you can have for example 6 functions open waiting for the child to be executed. If you have a pointer to store the path, then you will probably mess up the output for the parent function, because they continue to calculate data for the current path and this path should not be changed by the called function.
"Applications" section implies a ready-made application, and possibly without a source code.
AZJIO wrote: ↑Tue Feb 21, 2023 7:04 pm
Use the s.String structure, then you will have both a string and a pointer without having to use PeekS.
It's a difference without a distinction, so why does it matter?
AZJIO wrote: ↑Tue Feb 21, 2023 7:04 pmIf you have a pointer to store the path, then you will probably mess up the output for the parent function, because they continue to calculate data for the current path and this path should not be changed by the called function.
The path isn't changed by the calling function, so your point is irrelevant.
AZJIO wrote: ↑Tue Feb 21, 2023 7:04 pm"Applications" section implies a ready-made application, and possibly without a source code.