Search code examples
.netvb.netfilefile-iodirectoryinfo

Improve this function to get recursively all files inside a directory


I need is to implement the file recursivity in this function to get all the files inside the subdirectories.

I want to preserve the efficiency of the function (I mean to avoid the using of large loops inside folders)

How I can do it?

EDIT: Also I need to put a Boolean arg to let me select if I want enable recursivity or not.

' For Each file In Get_Files("C:\Windows", {".dll", ".ini"}) : MsgBox(file.Name) : Next

Private Function Get_Files(ByVal Path As String, ParamArray exts() As String) As List(Of IO.FileInfo)
    Return New IO.DirectoryInfo(Path).GetFiles.Where(Function(o) exts.Contains(o.Extension)).ToList
End Function

UPDATE

I need to preserve in the dotINSolution modification the eficiency of the original code which returns a list of IO.FileInfo instead a list of string:

Private Function Get_Files(ByVal Path As String, ByVal Recursive As Boolean, ParamArray exts() As String) As List(Of String) ' As List(Of IO.FileInfo)
    Select Case Recursive
        Case True : Return IO.Directory.GetFiles(Path, "*.*", IO.SearchOption.AllDirectories).Where(Function(o) exts.Contains(IO.Path.GetExtension(o))).ToList
        Case False : Return IO.Directory.GetFiles(Path, "*.*", IO.SearchOption.TopDirectoryOnly).Where(Function(o) exts.Contains(IO.Path.GetExtension(o))).ToList
    End Select
End Function

Is this possibly without doing major changes or without converting the result more than one time?


Solution

  • All you need to do get a list of FileInfo instead of filenames is create a new FileInfo for each file, like this:

    Private Function Get_Files(ByVal rootDirectory As String, ByVal recursive As Boolean, ParamArray exts() As String) As List(Of IO.FileInfo)
        Dim searchOpt As IO.SearchOption = If(recursive, IO.SearchOption.AllDirectories, IO.SearchOption.TopDirectoryOnly)
        Return IO.Directory.GetFiles(rootDirectory, "*.*", searchOpt).Where(Function(o) exts.Contains(IO.Path.GetExtension(o))).Select(Function(p) New IO.FileInfo(p)).ToList
    End Function
    

    And if you use Imports System.IO at the top of your code, you don't need to type IO. so much and it will look tidier.

    EDIT:

    For a case-sensitive test of the extension, you could implement the comparer in the Enumerable.Contains method:

    Public Class FilenameExtensionComparer
        Implements IEqualityComparer(Of String)
    
        Public Function Equals1(s As String, t As String) As Boolean Implements IEqualityComparer(Of String).Equals
            Return String.Compare(s, t, StringComparison.OrdinalIgnoreCase) = 0
        End Function
    
        Public Function GetHashCode1(s As String) As Integer Implements IEqualityComparer(Of String).GetHashCode
            Return s.GetHashCode()
        End Function
    
    End Class
    
    Private Function Get_Files(ByVal rootDirectory As String, ByVal recursive As Boolean, ParamArray exts() As String) As List(Of IO.FileInfo)
        Dim searchOpt As IO.SearchOption = If(recursive, IO.SearchOption.AllDirectories, IO.SearchOption.TopDirectoryOnly)
        Dim filenameExtComparer As New FilenameExtensionComparer
        Return IO.Directory.GetFiles(rootDirectory, "*.*", searchOpt).Where(Function(o) exts.Contains(IO.Path.GetExtension(o), filenameExtComparer)).Select(Function(p) New IO.FileInfo(p)).ToList
    End Function
    

    I sense feature-creep in this question ;) You should have a look at the documentation for the .NET methods which are used and see if they have overloads which are useful to you.

    EDIT 2: Oops, I see you wanted case-insensitivity. I adjusted the comparer appropriately.