Page 1 of 1
CountFiles()
Posted: Sun Jul 03, 2016 11:41 pm
by Thunder93
Code: Select all
Global NewList cfNames.s()
Global NewList cfTypes.s()
;{ Windows Specific Procedure }
Procedure.i CountFiles(Path.s, Ignore_SubDIRs.b = 0, State.b = 1)
Protected _Data.WIN32_FIND_DATA, Path$ = Path + "\*.*", IsTrue.b
Static Files
If State : Files = 0 : EndIf
hF = FindFirstFile_(Path$, @_Data)
If hF <> #INVALID_HANDLE_VALUE
Repeat
If _Data\dwFileAttributes & #FILE_ATTRIBUTE_DIRECTORY
If Ignore_SubDIRs = 1 : Continue : EndIf
;// skip file or directory that has an associated reparse point,
;// or a file that is a symbolic link. Basically to avoid potential
;// infinitely recursive directory tree.
If Not _Data\dwFileAttributes & #FILE_ATTRIBUTE_REPARSE_POINT
;// make sure we skip "." And ".."
;// some file names can start With a dot, so just testing For the
;// first dot is Not suffient.
If PeekS(@_Data\cFileName) <> "." And PeekS(@_Data\cFileName) <> ".."
;// We found a sub-directory, so get the files in it too
Path$ = Path + "\" + PeekS(@_Data\cFileName)
;// recurrsion here!
CountFiles(Path$, 0, 0) ; Traverse Directory
EndIf
EndIf
Else
ForEach cfTypes()
If cfTypes() = GetExtensionPart(PeekS(@_Data\cFileName))
IsTrue = 1
Break
EndIf
Next
If IsTrue = 1 : IsTrue = 0 : Continue : EndIf
ForEach cfNames()
If cfNames() = GetFilePart(PeekS(@_Data\cFileName))
IsTrue = 1
Break
EndIf
Next
If IsTrue = 1 : IsTrue = 0 : Continue : EndIf
Files + 1
EndIf
Until FindNextFile_(hF, @_Data) = 0
FindClose_(hF)
EndIf
ProcedureReturn Files
EndProcedure
;}
Procedure.b AddFiletype(Str$)
If AddElement(cfTypes()) <> 0
cfTypes() = Str$
ProcedureReturn 1
EndIf
EndProcedure
Procedure.b AddFilename(Str$)
If AddElement(cfNames()) <> 0
cfNames() = Str$
ProcedureReturn 1
EndIf
EndProcedure
Procedure.b DelFiletype(Str$)
ForEach cfTypes()
If cfTypes() = Str$
DeleteElement(cfTypes())
ProcedureReturn 1
EndIf
Next
EndProcedure
Procedure.b DelFilename(Str$)
ForEach cfNames()
If cfNames() = Str$
DeleteElement(cfNames())
ProcedureReturn 1
EndIf
Next
EndProcedure
Procedure.b ClearFilenames()
ClearList(cfNames())
EndProcedure
Procedure.b ClearFiletypes()
ClearList(cfTypes())
EndProcedure
CompilerIf #PB_Compiler_IsMainFile
Path.s = #PB_Compiler_Home
Debug "CountFiles()"
Debug "Path: " + Path
Debug " "+CountFiles(Path, 1) + " Files. Excluded SubDirectories."
; Debug " "+CountFiles(Path) + " Regular, Include SubDirectories."
AddFiletype("exe")
Debug " "+CountFiles(Path, 1) + " Files. Excluded executables filetypes. Excluded SubDirectories."
DelFiletype("exe")
AddFilename("PureBasic.exe")
Debug " "+CountFiles(Path, 1) + " Files. Excluded file: PureBasic.exe. Excluded SubDirectories."
AddFilename("unins000.exe")
Debug " "+CountFiles(Path, 1) + " Files. Excluded files: PureBasic.exe and unins000.exe. Excluded SubDirectories."
ClearFilenames() : ClearFiletypes()
Debug " "
Debug " "+CountFiles(Path) + " Files. SubDirectories Included."
AddFiletype("exe")
Debug " "+CountFiles(Path) + " Files. Excluded executables filetypes. SubDirectories Included."
AddFilename("PureBasic.chm")
Debug " "+CountFiles(Path) + " Files. Excluded file: PureBasic.chm. Excluded executables filetypes. Included SubDirectories."
CompilerEndIf
Debugging Output:
CountFiles()
Path: D:\Program Files\PureBasic 5.42\
- 4 Files. Excluded SubDirectories.
2 Files. Excluded executables filetypes. Excluded SubDirectories.
3 Files. Excluded file: PureBasic.exe. Excluded SubDirectories.
2 Files. Excluded files: PureBasic.exe and unins000.exe. Excluded SubDirectories.
937 Files. SubDirectories Included.
922 Files. Excluded executables filetypes. SubDirectories Included.
921 Files. Excluded file: PureBasic.chm. Excluded executables filetypes. Included SubDirectories.
Click
Here to jump to the later post with enhanced version of CountFiles(), also using PB native commandset.
Re: CountFiles (Windows-specific)
Posted: Mon Jul 04, 2016 3:58 am
by Thunder93
Little more enhanced.
Code: Select all
Global NewList cfNames.s()
Global NewList cfTypes.s()
Global NewList cDirectories.s()
;{ Windows Specific Procedure }
Procedure.i CountFiles(Path.s, Ignore_SubDIRs.b = 0, State.b = 1)
Protected _Data.WIN32_FIND_DATA, Path$ = Path + "\*.*", IsTrue.b, StrAd.s = "\"
Static Files
If Right(Path, 1) = "\" : StrAd = "" : EndIf
If State : Files = 0 : EndIf
hF = FindFirstFile_(Path$, @_Data)
If hF <> #INVALID_HANDLE_VALUE
Repeat
If _Data\dwFileAttributes & #FILE_ATTRIBUTE_DIRECTORY
If Ignore_SubDIRs = 1 : Continue : EndIf
;// skip file or directory that has an associated reparse point,
;// or a file that is a symbolic link. Basically to avoid potential
;// infinitely recursive directory tree.
If Not _Data\dwFileAttributes & #FILE_ATTRIBUTE_REPARSE_POINT
;// make sure we skip "." And ".."
;// some file names can start With a dot, so just testing For the
;// first dot is Not suffient.
If PeekS(@_Data\cFileName) <> "." And PeekS(@_Data\cFileName) <> ".."
;// We found a sub-directory, so get the files in it too
Path$ = Path + StrAd + PeekS(@_Data\cFileName)
ForEach cDirectories()
If cDirectories() = LCase(fName)
IsTrue = 1
Break
EndIf
Next
If IsTrue = 1 : IsTrue = 0 : Continue : EndIf
;// recurrsion here!
CountFiles(Path$, 0, 0) ; Traverse Directory
EndIf
EndIf
Else
ForEach cfTypes()
If cfTypes() = LCase(GetExtensionPart(PeekS(@_Data\cFileName)))
IsTrue = 1
Break
EndIf
Next
If IsTrue = 1 : IsTrue = 0 : Continue : EndIf
ForEach cfNames()
If cfNames() = LCase(GetFilePart(PeekS(@_Data\cFileName)))
IsTrue = 1
Break
EndIf
Next
If IsTrue = 1 : IsTrue = 0 : Continue : EndIf
Files + 1
EndIf
Until FindNextFile_(hF, @_Data) = 0
FindClose_(hF)
EndIf
ProcedureReturn Files
EndProcedure
;}
Procedure.b AddFilename(Str$)
If AddElement(cfNames()) <> 0
cfNames() = LCase(Str$)
ProcedureReturn 1
EndIf
EndProcedure
Procedure.b AddFiletype(Str$)
If AddElement(cfTypes()) <> 0
cfTypes() = LCase(Str$)
ProcedureReturn 1
EndIf
EndProcedure
Procedure.b AddDirectory(Str$)
If Right(Str$, 1) = "\" : Str$ = Mid(Str$, 0, Len(Str$)-1) : EndIf
If AddElement(cDirectories()) <> 0
cDirectories() = LCase(Str$)
ProcedureReturn 1
EndIf
EndProcedure
Procedure.b DelFilename(Str$)
ForEach cfNames()
If cfNames() = LCase(Str$)
DeleteElement(cfNames())
ProcedureReturn 1
EndIf
Next
EndProcedure
Procedure.b DelFiletype(Str$)
ForEach cfTypes()
If cfTypes() = LCase(Str$)
DeleteElement(cfTypes())
ProcedureReturn 1
EndIf
Next
EndProcedure
Procedure.b DelDirectory(Str$)
If Right(Str$, 1) = "\" : Str$ = Mid(Str$, 0, Len(Str$)-1) : EndIf
ForEach cDirectories()
If cDirectories() = LCase(Str$)
DeleteElement(cDirectories())
ProcedureReturn 1
EndIf
Next
EndProcedure
Procedure.b ClearFilenames()
ClearList(cfNames())
EndProcedure
Procedure.b ClearFiletypes()
ClearList(cfTypes())
EndProcedure
Procedure.b ClearDirectories()
ClearList(cDirectories())
EndProcedure
Procedure.b ClearFilters()
ClearList(cfNames()) : ClearList(cfTypes()) : ClearList(cDirectories())
EndProcedure
CompilerIf #PB_Compiler_IsMainFile
Path.s = #PB_Compiler_Home
Debug "CountFiles()"
Debug "Path: " + Path
Debug " "+CountFiles(Path, 1) + " Files. Excluded SubDirectories."
; Debug " "+CountFiles(Path) + " Regular, Include SubDirectories."
AddFiletype("exe") ; Add filetype to be excluded from search.
Debug " "+CountFiles(Path, 1) + " Files. Excluded executables filetypes. Excluded SubDirectories."
DelFiletype("exe") ; Add filetype to be excluded from search.
AddFilename("PureBasic.exe") ; Add file to be excluded from search.
Debug " "+CountFiles(Path, 1) + " Files. Excluded file: PureBasic.exe. Excluded SubDirectories."
AddFilename("unins000.exe") ; Add another file to be excluded from search.
Debug " "+CountFiles(Path, 1) + " Files. Excluded files: PureBasic.exe and unins000.exe. Excluded SubDirectories."
ClearFilters() ; Clear all Filters
Debug " "
Debug " "+CountFiles(Path) + " Files. SubDirectories Included."
AddFiletype("exe") ; Add filetype to be excluded from search.
Debug " "+CountFiles(Path) + " Files. Excluded executables filetypes. SubDirectories Included."
AddFilename("PureBasic.chm") ; Add file to be excluded from search.
Debug " "+CountFiles(Path) + " Files. Excluded file: PureBasic.chm. Excluded executables filetypes. Included SubDirectories."
ClearFilters() ; Clear all Filters
AddDirectory("D:\Program Files\PureBasic 5.42\Catalogs\Francais") ; Add Directory to be excluded from search.
Debug " "+CountFiles(Path) + " Files. Excluded SubDirectory ...\Catalogs\Francais\. SubDirectories Included."
CompilerEndIf
CountFiles()
Path: D:\Program Files\PureBasic 5.42\
- 4 Files. Excluded SubDirectories.
2 Files. Excluded executables filetypes. Excluded SubDirectories.
3 Files. Excluded file: PureBasic.exe. Excluded SubDirectories.
2 Files. Excluded files: PureBasic.exe and unins000.exe. Excluded SubDirectories.
937 Files. SubDirectories Included.
922 Files. Excluded executables filetypes. SubDirectories Included.
921 Files. Excluded file: PureBasic.chm. Excluded executables filetypes. Included SubDirectories.
933 Files. Included SubDirectories. Excluded SubDirectory ...\Catalogs\Francais\.
Re: CountFiles (Windows-specific)
Posted: Mon Jul 04, 2016 4:09 pm
by blueb
Very fast!
CountFiles()
Path: E:\PureBasic\
43 Files. Excluded SubDirectories.
34 Files. Excluded executables filetypes. Excluded SubDirectories.
42 Files. Excluded file: PureBasic.exe. Excluded SubDirectories.
41 Files. Excluded files: PureBasic.exe and unins000.exe. Excluded SubDirectories.
50750 Files. SubDirectories Included.
49420 Files. Excluded executables filetypes. SubDirectories Included.
49419 Files. Excluded file: PureBasic.chm. Excluded executables filetypes. Included SubDirectories.
E:\PureBasic\Catalogs\Francais
50746 Files. Excluded SubDirectory ...\Catalogs\Francais\. SubDirectories Included.
(I checked and there are 4 files in the above sub-directory)
This took 914 milliseconds!
Re: CountFiles (Windows-specific)
Posted: Mon Jul 04, 2016 4:35 pm
by Thunder93
Just as easy to make a cross-platform supported version. ....Removed some text
Re: CountFiles (Windows-specific)
Posted: Mon Jul 04, 2016 4:45 pm
by Kukulkan
Short question: Is PB not simply using FindFirstFile_() and FindNextFile_() API in the background if we use the PB native functions? Is this function really faster than PB only? And why?
Re: CountFiles (Windows-specific)
Posted: Mon Jul 04, 2016 5:13 pm
by Thunder93
I never analyzed but I believe PB uses FindFirstFile_() and FindNextFile_() API. Using directly the APIs can shave off a little processing time. Typically not significant enough to be concerned about.
Blueb can come on here and correct me if I'm wrong, however I imagine what he meant by “very fast”. For what it does all, its speedy. Not a comparison to the PB native counterpart.
Re: CountFiles (Windows-specific)
Posted: Mon Jul 04, 2016 5:59 pm
by blueb
That's right Thunder93.
As you can see from my previous post, I have a lot of files in my PureBasic directory...
4.36 GB (4,685,593,928 bytes) to be exact,
and I can run the example program in under 1 second.
Using a mid-range CPU (i7-2600 CPU)
Fast enough for most uses.

Re: CountFiles (Windows-specific)
Posted: Mon Jul 04, 2016 6:30 pm
by Thunder93
Was that from running via Debugger or executable execution? Always even faster via executable execution

Re: CountFiles (Windows-specific)
Posted: Mon Jul 04, 2016 7:59 pm
by blueb
Nope... used sample program and Debug.
Removed Debug commands to check for differences...
Now the speed is: 839 milliseconds for the EXE (small difference)

Re: CountFiles (Windows-specific)
Posted: Tue Jul 05, 2016 5:13 am
by Thunder93
The enhanced version, however uses PB native commandset.
Code: Select all
Global NewList cfNames.s()
Global NewList cfTypes.s()
Global NewList cDirectories.s()
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
#PB_FileSystem_Link = #FILE_ATTRIBUTE_REPARSE_POINT
CompilerEndIf
Procedure CountFiles(Path.s, Ignore_SubDIRs.b = 0, State.b = 1)
Protected Path$, IsTrue.b, StrAd.s = "\"
Static Files
If Right(Path, 1) = "\" : StrAd = "" : EndIf
If State : Files = 0 : EndIf
hF = ExamineDirectory(#PB_Any, Path, "*.*")
If hF <> #False
While NextDirectoryEntry(hF)
If DirectoryEntryType(hF) = #PB_DirectoryEntry_Directory
If Ignore_SubDIRs = 1: Continue : EndIf
If DirectoryEntryName(hF) <> "." And DirectoryEntryName(hF) <> ".."
If DirectoryEntryAttributes(hF) & #PB_FileSystem_Link
Continue
EndIf
Path$ = Path + StrAd + DirectoryEntryName(hF)
ForEach cDirectories()
If cDirectories() = LCase(Path$)
IsTrue = 1
Break
EndIf
Next
If IsTrue = 1 : IsTrue = 0 : Continue : EndIf
;// recurrsion here!
CountFiles(Path$, 0, 0) ; Traverse Directory
EndIf
Else
ForEach cfTypes()
If cfTypes() = LCase(GetExtensionPart(DirectoryEntryName(hF)))
IsTrue = 1
Break
EndIf
Next
If IsTrue = 1 : IsTrue = 0 : Continue : EndIf
ForEach cfNames()
If cfNames() = LCase(GetFilePart(DirectoryEntryName(hF)))
IsTrue = 1
Break
EndIf
Next
If IsTrue = 1 : IsTrue = 0 : Continue : EndIf
Files + 1
EndIf
Wend
FinishDirectory(hF)
EndIf
ProcedureReturn Files
EndProcedure
Procedure.b AddFilename(Str$)
If AddElement(cfNames()) <> 0
cfNames() = LCase(Str$)
ProcedureReturn 1
EndIf
EndProcedure
Procedure.b AddFiletype(Str$)
If AddElement(cfTypes()) <> 0
cfTypes() = LCase(Str$)
ProcedureReturn 1
EndIf
EndProcedure
Procedure.b AddDirectory(Str$)
If Right(Str$, 1) = "\" : Str$ = Mid(Str$, 0, Len(Str$)-1) : EndIf
If AddElement(cDirectories()) <> 0
cDirectories() = LCase(Str$)
ProcedureReturn 1
EndIf
EndProcedure
Procedure.b DelFilename(Str$)
ForEach cfNames()
If cfNames() = LCase(Str$)
DeleteElement(cfNames())
ProcedureReturn 1
EndIf
Next
EndProcedure
Procedure.b DelFiletype(Str$)
ForEach cfTypes()
If cfTypes() = LCase(Str$)
DeleteElement(cfTypes())
ProcedureReturn 1
EndIf
Next
EndProcedure
Procedure.b DelDirectory(Str$)
If Right(Str$, 1) = "\" : Str$ = Mid(Str$, 0, Len(Str$)-1) : EndIf
ForEach cDirectories()
If cDirectories() = LCase(Str$)
DeleteElement(cDirectories())
ProcedureReturn 1
EndIf
Next
EndProcedure
Procedure.b ClearFilenames()
ClearList(cfNames())
EndProcedure
Procedure.b ClearFiletypes()
ClearList(cfTypes())
EndProcedure
Procedure.b ClearDirectories()
ClearList(cDirectories())
EndProcedure
Procedure.b ClearFilters()
ClearList(cfNames()) : ClearList(cfTypes()) : ClearList(cDirectories())
EndProcedure
CompilerIf #PB_Compiler_IsMainFile
Path.s = #PB_Compiler_Home
Str$ = "CountFiles()"+#LF$
Str$ + "Path: " + Path+#LF$+#LF$
StartTime = ElapsedMilliseconds()
Str$ + " "+CountFiles(Path, 1) + " Files. Excluded SubDirectories."+#LF$
; Debug " "+CountFiles(Path) + " Regular, Include SubDirectories."
AddFiletype("exe") ; Add filetype to be excluded from search.
Str$ + " " + CountFiles(Path, 1) + " Files. Excluded executables filetypes. Excluded SubDirectories."+#LF$
DelFiletype("exe") ; Add filetype to be excluded from search.
AddFilename("PureBasic.exe") ; Add file to be excluded from search.
Str$ + " " + CountFiles(Path, 1) + " Files. Excluded file: PureBasic.exe. Excluded SubDirectories."+#LF$
AddFilename("unins000.exe") ; Add another file to be excluded from search.
Str$ + " " + CountFiles(Path, 1) + " Files. Excluded files: PureBasic.exe and unins000.exe. Excluded SubDirectories."+#LF$
ClearFilters() ; Clear all Filters
Str$ + " "+#LF$
Str$ + " " + CountFiles(Path) + " Files. SubDirectories Included."+#LF$
AddFiletype("exe") ; Add filetype to be excluded from search.
Str$ + " " + CountFiles(Path) + " Files. Excluded executables filetypes. SubDirectories Included."+#LF$
AddFilename("PureBasic.chm") ; Add file to be excluded from search.
Str$ + " " + CountFiles(Path) + " Files. Excluded file: PureBasic.chm. Excluded executables filetypes. Included SubDirectories."+#LF$
ClearFilters() ; Clear all Filters
AddDirectory("D:\Program Files\PureBasic 5.42\Catalogs\Francais") ; Add Directory to be excluded from search.
Str$ + " " + CountFiles(Path) + " Files. Included SubDirectories. Excluded SubDirectory ...\Catalogs\Francais\."+#LF$+#LF$
ElapsedTime = ElapsedMilliseconds()-StartTime
Str$ + "Runtime: " + Str(ElapsedTime)+"ms"
SetClipboardText(Str$)
MessageRequester("Information", Str$, #PB_MessageRequester_Ok)
CompilerEndIf