You can shell() any command, whether DOS or PS. If you don't think Net is faster than API, then you should test. I'd think .Net framework is a magnitude of order faster. Come up with some sort of test, and I'll run it.
Printable View
I know you can shell but then there is the matter of getting the results, pretty much the same as if you used the dir /s method. Once it completes then you must parse out the file generated and search for the results there.
As for the speed I have not did a lot of comparisson but in general API commands are typically pretty quick where the .net routines seem to be rather sluggish especially on the first run when the framework may not already be loaded into memory of the system.
Think about the memory required? How many bytes do you think are used to load the .net framework and do a simple dir listing? How many would you think is needed for Dos Dir or VB Dir. my guess would be that .net is more than double the combination of the 2.
You can do all kinds of parsing, or formatting. You can send the results to a list, or a listbox. Doesn't matter.
Once you have W2K8 Server Core, there is NO GUI at all. Powershell is the only way to operate the server
This adds "Pattern" as 'search file type' to the procedure:
Why I was referring to making two passes is this:Code:Private Sub ListAllFilesDIR(ByVal StartingFolder As String, Pattern As String)
Dim CurDir As String
Dim CurName As String
Dim Dirs As New Collection
Dim FullName As String
If Right$(StartingFolder, 1) <> "\" Then StartingFolder = StartingFolder + "\"
Dirs.Add StartingFolder
While Dirs.Count
CurDir = Dirs(1)
Dirs.Remove 1
CurName = Dir$(CurDir, vbDirectory)
While CurName <> ""
If CurName <> "." And CurName <> ".." Then
FullName = CurDir + CurName
If GetAttr(FullName) And vbDirectory Then Dirs.Add FullName + "\"
If CurName Like Pattern Then lstFiles.AddItem FullName
End If
CurName = Dir$
Wend
Wend
End Sub
If you do Dir$("*.*") file type matching takes place and also files with no extension are found.
Doing pattern matching with the 'Like' operator is a little different.
"*" will match ALL names
"*.*" will only match names with a dot in it, in fact which have an extension.
You have to know that to give a clear match pattern. In the above case you don't need an extra pass with Dir$(Pattern), but you'd have to know that *.* as a pattern would not, as would be expected from usual wildcarding, include files with no extension.
Concerning first run:
ALL variations, API, DIR or FSO are slower on the first run. I think this is because windows caches directory searches extensively. Second search of the same folders is much faster, no matter which technique is used.
With the dir function, you can use the pattern ("*.*") directly in the dir call, however only one pattern at a time...
will return files without a period extension e.g. thisfilenamewithnoextensionCode:ReturnString = Dir(InitialPath & SearchPattern, SearchAttributes)
'CurName = Dir$(CurDir & "*.*", vbDirectory)
(which also means I need to modify some code I have...)
You have to look at the whole loop:
If you'd change the line of the first Dir call toCode:CurName = Dir$(CurDir, vbDirectory)
While CurName <> ""
If CurName <> "." And CurName <> ".." Then
FullName = CurDir + CurName
If GetAttr(FullName) And vbDirectory Then Dirs.Add FullName + "\"
If CurName Like Pattern Then lstFiles.AddItem FullName
End If
CurName = Dir$
Wend
CurName = Dir$(CurDir & Pattern, vbDirectory)
you are fooled, except the pattern is "*.*", which it is by default if omitted.
But if you called for "*.jpg" for instance it will also only find folders which end in ".jpg"
It is working and it is searching subfolders.
But, still not enough quick, because of the numbers of searching subfolders (about 500) and searching files (about 250).
The number of subfolders and searching files will rise very quick in future.
Therefore I am looking for a quicker solution.
Thanks for many fine initiatives.
It always depends what to do with the filename strings.
Adding them to a listbox is time consuming the more files and the longer the pathes.
If you only search for distinct names you wouldn't find anything faster'n that. Not in VB6.
After some discussion with vb5prgrmr behind the curtains, and after some more fiddling I want to present you with the fastest scan loop I could produce. It uses API and needs the declarations of FindFirstFile(), FindNextFile() and WIN32_FIND_DATA as shown before.
The fastest way to test is to set lstFiles.Visible=False before calling this and then set visibility back on again.
It lists all files in the given folder and in all subfolders.Code:Private Sub ListAllFilesAPI(ByVal StartingFolder As String)
' trying to do API search with only one pass
Dim CurName As String, CurFull As String, CurDir As String
Dim Dirs As New Collection
Dim hSearch As Long
Dim WFD As WIN32_FIND_DATA
Dim i%, cont&
If Right$(StartingFolder, 1) <> "\" Then StartingFolder = StartingFolder + "\"
Dirs.Add StartingFolder
While Dirs.Count
CurDir = Dirs(1)
Dirs.Remove 1
cont = 1
hSearch = FindFirstFile(CurDir + "*", WFD)
If hSearch <> INVALID_HANDLE_VALUE Then
Do While cont
CurName = StripNulls(WFD.cFileName)
If CurName <> "." And CurName <> ".." Then
CurFull = StartingFolder + CurName
If GetFileAttributes(CurFull) And FILE_ATTRIBUTE_DIRECTORY Then Dirs.Add CurName
lstFiles.AddItem CurFull
End If
cont = FindNextFile(hSearch, WFD)
Loop
End If
Wend
End Sub
To work with pattern matching evenly fast you should add the Pattern parameter and use the Like operator in the line:
If CurName Like Pattern then lstFiles.AddItem CurFull
Where are the numbers??? Your fast dir vs your fast API?
Well, yes, just you wait. I still discovered a mistake in the above routine. Have to look for it.
Ok, for a final conclusion and figures now, here is this.
This is the fastest I could work out.Code:Public Sub ListAllFilesAPI(ByVal StartingFolder As String)
' trying to do API search with only one pass
Dim CurName As String, CurFull As String, CurDir As String
Dim Dirs As New Collection
Dim hSearch As Long
Dim WFD As WIN32_FIND_DATA
Dim i%, cont&
If Right$(StartingFolder, 1) <> "\" Then StartingFolder = StartingFolder + "\"
Dirs.Add StartingFolder
While Dirs.Count
CurDir = Dirs(1)
If Right$(CurDir, 1) <> "\" Then CurDir = CurDir + "\"
Dirs.Remove 1
cont = 1
hSearch = FindFirstFile(CurDir + "*.*", WFD)
If hSearch <> INVALID_HANDLE_VALUE Then
Do While cont
CurName = StripNulls(WFD.cFileName)
If CurName <> "." And CurName <> ".." Then
CurFull = CurDir + CurName
If GetFileAttributes(CurFull) And FILE_ATTRIBUTE_DIRECTORY Then
Dirs.Add CurFull
MainForm.lstFiles.AddItem CurFull
Else
MainForm.lstFiles.AddItem CurName
End If
End If
cont = FindNextFile(hSearch, WFD)
Loop
DoEvents
End If
cont = FindClose(hSearch)
Wend
End Sub
I benched it with a folder that contains 44700 files in 6 subfolders.
Runtime for this was about 4.5 seconds.
The same procedure done with Dir instead of API was amazingly only 4.7 seconds, not very much slower than the API call.
Your procedure vb5prgrmr took 4.9 seconds, despite its heavy error checking a very good result.
Edit: after running both Dir and API calls several time I found execution time varies about 150ms, so as I can only say API and Dir givces nearly the same result.
Well, you should see what powershell does.
You are adding them to a lb, how about a file?
I've been using this for a LONG time to keep track of folder/file names:
If you write the other versions, I'll write a PS version. I can test, or you can test, as I have a current list of files (no timer yet)
Code:Option Explicit
' (c) Siok Online 2006
' David Glienna
Dim fn$, rt%, j$
'
' Add a reference to Microsoft Scripting Control
Private Sub Form_Load()
j = ""
Open App.Path & "\list.txt" For Output As #1
Print #1, " Visual Basic Samples - " & Format(Date, "MMMM d, YYYY")
Print #1, ""
Print #1, "C:\Visual Basic Samples\"
Print #1, ""
RecurseFolderList "C:\Visual Basic Samples" ' You can use a folder or drive
Print #1, ""
Print #1, "Total Number of Programs : " & rt
Print #1, ""
Print #1, " (c) SIOK Online 2008"
Print #1, " C:\Visual Basic Samples\S\SearchforVBPfiles"
Close #1
MsgBox "Done."
Unload Me
End Sub
Public Function RecurseFolderList(FolderName As String) As Boolean
Dim f As Folder
Dim fc As Folders
Dim fj As Files
Dim f1 As Folder
Dim f2 As File
Dim fso As New FileSystemObject
If fso.FolderExists(FolderName) Then
Set f = fso.GetFolder(FolderName)
Set fc = f.SubFolders
Set fj = f.Files
'For each subfolder in the Folder
For Each f1 In fc
'Do something with the Folder Name
'Then recurse this function with the sub-folder to get any'
' sub-folders
RecurseFolderList (f1)
Next
'For each folder check for any files
DoEvents
For Each f2 In fj
If LCase(Right(f2.Name, 3)) = "vbp" Then
fn = f2.Name
If j <> Mid(f2, 25, 1) Then
j = Mid(f2, 25, 1)
fn = " " & Right(f2, Len(f2) - 24)
Else
fn = " - " & Right(f2, Len(f2) - 24)
End If
Print #1, fn
rt = rt + 1
End If
Next
Set f = Nothing
Set fc = Nothing
Set fj = Nothing
Set f1 = Nothing
Else
RecurseFolderList = False
End If
Set fso = Nothing
End Function
I tried your ListAllFilesDir function on my system
took 11.6 seconds to scan 42,956 files in 4,519 folders
AMD X2 4400+ Windows XP MCE SP3
That was with a *.* filter
When I changed it to *.txt it took 1.7 seconds to scan the same folder and found 500 files in about 200 or so folders.