1
\$\begingroup\$

Well, I'm writing a piece of code that will take a list of file names and should search a local drive for each file, determine if it's there or not, and return an array of all the paths found.

Right now I'm using a function that searches for one file and I call this function for each file in the list:

Public Function DriveSearch(ByVal sDir As String, sFile As String) As String()
 Dim filesFound As New List(Of String)
 Try
 For Each dir As String In Directory.GetDirectories(sDir)
 For Each file In Directory.GetFiles(dir, sFile)
 filesFound.Add(file)
 Next
 filesFound.AddRange(DriveSearch(dir, sFile))
 Next
 Catch ex As Exception
 Console.WriteLine(ex.Message)
 End Try
 Return filesFound.ToArray
End Function

But I'm wondering if there's a faster way to achieve this. Maybe I should index all the files in the drive first before searching? (I'm not sure how to do this yet).

The number of files in the list is around 100 (for now) but it's likely to increase to couple thousands.


Edit:

I decided that I won't need the duplicates, so here's my current function:

Public Function DriveSearch(ByVal sDir As String, sFile As String) As String
 Dim filePath As String = String.Empty
 Try
 Dim arrFiles As String() = Directory.GetFiles(sDir, sFile)
 If arrFiles.Length > 0 Then
 filePath = arrFiles(0)
 Else
 For Each dir As String In Directory.GetDirectories(sDir)
 filePath = DriveSearch(dir, sFile)
 If filePath.Length > 0 Then Exit For
 Next
 End If
 Catch ex As Exception
 Console.WriteLine(ex.Message)
 End Try
 Return filePath
End Function

Still not sure if this is the fastest way to search for 100+ files.

asked Aug 25, 2016 at 12:13
\$\endgroup\$
3
  • \$\begingroup\$ Do you want to find all files which has the same filename ? \$\endgroup\$ Commented Aug 25, 2016 at 12:24
  • \$\begingroup\$ @Heslacher The answer is: not at the moment, but might be required later. I thought about excluding the filenames found but I'm not sure yet if will be required to find all matching files. \$\endgroup\$ Commented Aug 25, 2016 at 12:28
  • \$\begingroup\$ @Heslacher I just edited the question. Will appreciate if you have a look. Thanks \$\endgroup\$ Commented Aug 25, 2016 at 14:23

2 Answers 2

3
\$\begingroup\$

This seems to be faster by 5 seconds on 12:

Public Function DriveSearch(directory As String, pattern As String) As String()
 Dim filesFound As List(Of String) = Nothing
 Try
 filesFound = GetFilesRecurively(directory, pattern)
 Catch ex As Exception
 Console.WriteLine(ex.Message)
 End Try
 Return filesFound?.ToArray
End Function
Private Function GetFilesRecurively(directory As String, pattern As String) As List(Of String)
 Dim filesFound = IO.Directory.EnumerateDirectories(directory) _
 .AsParallel() _
 .SelectMany(Function(subDirectory) GetFilesRecurively(subDirectory, pattern)) _
 .ToList()
 filesFound.AddRange(IO.Directory.EnumerateFiles(directory, pattern))
 Return filesFound
End Function

This version beats them all taking only few milliseconds:

Public Function DriveSearch(directory As String, pattern As String) As String()
 Dim filesFound As List(Of String) = Nothing
 Try
 filesFound = IO.Directory.EnumerateFiles(directory, pattern, SearchOption.AllDirectories).ToList()
 Catch ex As Exception
 Console.WriteLine(ex.Message)
 End Try
 Return filesFound?.ToArray
End Function

You can also validate the arguments and save yourself a Try..Catch:

Public Function DriveSearch(path As String, pattern As String) As IEnumerable(Of String)
 Return If _
 (
 ArgumentsValid(path, pattern),
 Directory.EnumerateFiles(path, pattern, SearchOption.AllDirectories),
 Enumerable.Empty(Of String)
 )
End Function
Private Function ArgumentsValid(path As String, pattern As String) As Boolean
 If Not Directory.Exists(path) Then
 Console.WriteLine("Invalid path")
 Return False
 End If
 If pattern Is Nothing Then
 Console.WriteLine("Invalid pattern")
 Return False
 End If
 Return True
End Function
answered Aug 25, 2016 at 15:43
\$\endgroup\$
0
1
\$\begingroup\$

You could remove the recursion by putting the drives inside a queue. Also, in .NET we don't prefix variable with their data type.

Public Function DriveSearch(ByVal topDirectory As String, ByVal file As String) As String
 Dim directoriesToSearch As New Queue(Of String)
 Dim filePath As String = String.Empty
 directoriesToSearch.Enqueue(topDirectory)
 While directoriesToSearch.Count > 0
 Dim curDirectory As String = directoriesToSearch.Dequeue
 Dim files As String() = Directory.GetFiles(curDirectory, file)
 If files.Length > 0 Then
 filePath = files(0)
 directoriesToSearch.Clear()
 Else
 For Each dir As String In Directory.GetDirectories(curDirectory)
 directoriesToSearch.Enqueue(dir)
 Next
 End If
 End While
 Return filePath
End Function
answered Sep 1, 2016 at 15:47
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.