none
Search for files on a disk, but skip folders which can't be accessed RRS feed

  • Question

  • All

    I try to write a function which retrieves all files which meet a specific condition.

    So function below is ran with eg.   Dim results As ArrayList = SearchFilesOnDisk("c:\", "*.pst")
    The result should be a ArrayList with all PST-files found on the C-drive.
    The issue is my code crashed as soon a folder is not accessible for the user.  So I must built in some error checking to skip such folders.  I've tried this with a Try-function, but this seems not to work as expected.  It seems to run fine at the beginning, but after some "unaccessible" folders, the code quits.

    private Function SearchFilesOnDisk(ByVal path As String, ByVal filetype As String) As ArrayList
    
            Dim arr As New ArrayList
            Try
                Dim dirs As String() = Directory.GetDirectories(path)
                Dim dir As String
                For Each dir In dirs
    
                    arr.AddRange(SearchFilesOnDisk(dir, filetype))
                    Debug.Print("checking: " & dir)
                Next
            Catch ex As UnauthorizedAccessException
    
            End Try
    
            Dim files As String() = Directory.GetFiles(path, filetype)
            Dim file As String
            For Each file In files
                arr.Add(file)
            Next
            Return arr
        End Function

    Wednesday, May 16, 2018 2:05 PM

Answers

  • Use EnumerateFiles and EnumerateDirectories instead of the "Get" methods since the Enumerate methods give you an opportunity to fail on a specific entry without ending the entire listing.

    Something like:

    Public Function SafeFindFiles(startPath As String, fileType As String, Optional recordAccessExceptions As Boolean = True) As List(Of String)
        Dim result As New List(Of String)
    
        Using directoryEnumerator = IO.Directory.EnumerateDirectories(startPath).GetEnumerator
            Dim areMoreDirectories As Boolean = True
            Do
                Try
                    areMoreDirectories = directoryEnumerator.MoveNext
                    If Not areMoreDirectories Then Exit Do
                    Using fileEnumerator = IO.Directory.EnumerateFiles(directoryEnumerator.Current, fileType).GetEnumerator
                        Dim areMoreFiles As Boolean = True
                        Do
                            Try
                                areMoreFiles = fileEnumerator.MoveNext
                                If Not areMoreFiles Then Exit Do
                                result.Add(fileEnumerator.Current)
                            Catch uaExFile As UnauthorizedAccessException
                                If recordAccessExceptions Then result.Add("Unauthorized File Access")
                            End Try
                        Loop
                    End Using
                    result.AddRange(SafeFindFiles(directoryEnumerator.Current, fileType, recordAccessExceptions))
                Catch uaExDir As UnauthorizedAccessException
                    If recordAccessExceptions Then result.Add("Unauthorized Directory Access")
                End Try
            Loop
        End Using
    
        Return result
    End Function
    


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    • Marked as answer by ino_mart Thursday, May 17, 2018 6:26 AM
    Wednesday, May 16, 2018 2:56 PM
    Moderator

All replies

  • See if the example at the below link works for you:

    https://stackoverflow.com/questions/34923742/search-specific-extensions-in-a-directory-vb/34924036#34924036


    Paul ~~~~ Microsoft MVP (Visual Basic)

    Wednesday, May 16, 2018 2:17 PM
  • Hi

    I would suggest you add a section to trap 'any other' errors' I use a similar layout in one of my apps to do a similar task.

    This would alert you of other IO exceptions that can occur.

        Try
    
          ' ,,,,,,,
    
    
        Catch ex As UnauthorizedAccessException
    
        Catch ex As Exception
          MessageBox.Show(ex.Message)
        End Try


    Regards Les, Livingston, Scotland


    • Edited by leshay Wednesday, May 16, 2018 2:21 PM
    Wednesday, May 16, 2018 2:20 PM
  • Use EnumerateFiles and EnumerateDirectories instead of the "Get" methods since the Enumerate methods give you an opportunity to fail on a specific entry without ending the entire listing.

    Something like:

    Public Function SafeFindFiles(startPath As String, fileType As String, Optional recordAccessExceptions As Boolean = True) As List(Of String)
        Dim result As New List(Of String)
    
        Using directoryEnumerator = IO.Directory.EnumerateDirectories(startPath).GetEnumerator
            Dim areMoreDirectories As Boolean = True
            Do
                Try
                    areMoreDirectories = directoryEnumerator.MoveNext
                    If Not areMoreDirectories Then Exit Do
                    Using fileEnumerator = IO.Directory.EnumerateFiles(directoryEnumerator.Current, fileType).GetEnumerator
                        Dim areMoreFiles As Boolean = True
                        Do
                            Try
                                areMoreFiles = fileEnumerator.MoveNext
                                If Not areMoreFiles Then Exit Do
                                result.Add(fileEnumerator.Current)
                            Catch uaExFile As UnauthorizedAccessException
                                If recordAccessExceptions Then result.Add("Unauthorized File Access")
                            End Try
                        Loop
                    End Using
                    result.AddRange(SafeFindFiles(directoryEnumerator.Current, fileType, recordAccessExceptions))
                Catch uaExDir As UnauthorizedAccessException
                    If recordAccessExceptions Then result.Add("Unauthorized Directory Access")
                End Try
            Loop
        End Using
    
        Return result
    End Function
    


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    • Marked as answer by ino_mart Thursday, May 17, 2018 6:26 AM
    Wednesday, May 16, 2018 2:56 PM
    Moderator
  • Take a look at this

        Private Function SearchForFilesOnDisk(Path As String, Optional SearchPattern As String = "") As String()
            Dim rv As String() = {""}
            SearchForFilesTime.Restart()
            If IO.Directory.Exists(Path) Then
                SearchForFilesRslts = New Concurrent.BlockingCollection(Of FileEnt)
                SearchForFiles(Path, SearchPattern)
                rv = (From ent In SearchForFilesRslts
                       Order By ent.dir, ent.file
                         Select IO.Path.Combine(ent.dir, ent.file)).ToArray
            End If
            SearchForFilesTime.Stop()
            Return rv
        End Function
    
        Private SearchForFilesTime As New Stopwatch
        Private SearchForFilesRslts As New Concurrent.BlockingCollection(Of FileEnt)
        Private Sub SearchForFiles(Path As String, Optional SearchPattern As String = "")
            Try
                Dim files() As String
                If SearchPattern = "" Then
                    files = IO.Directory.GetFiles(Path)
                Else
                    files = IO.Directory.GetFiles(Path, SearchPattern)
                End If
                For Each f As String In files
                    Dim fe As New FileEnt
                    fe.dir = Path
                    fe.file = IO.Path.GetFileName(f)
                    SearchForFilesRslts.Add(fe)
                Next
    
                Dim dirs() As String = IO.Directory.GetDirectories(Path)
                Parallel.ForEach(dirs, Sub(CurDir)
                                           SearchForFiles(CurDir, SearchPattern)
                                       End Sub)
    
            Catch ex As UnauthorizedAccessException
    
            Catch ex As Exception
    
            End Try
        End Sub
    
        Private Class FileEnt
            Public dir As String
            Public file As String
        End Class
    

    to test it

            Dim path As String = ""
            'path = "c:\"
            'path = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86)
            path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
    
            RichTextBox1.Lines = SearchForFilesOnDisk(path, "*.pdf")
            RichTextBox1.AppendText(Environment.NewLine)
            RichTextBox1.AppendText(SearchForFilesRslts.Count.ToString("n0"))
            RichTextBox1.AppendText(Environment.NewLine)
            RichTextBox1.AppendText(SearchForFilesTime.Elapsed.ToString)
    


    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it."

    - from former MSDN User JohnWein

    SerialPort Info

    Multics - An OS ahead of its time.

    Wednesday, May 16, 2018 4:02 PM
  • Hello,

    The following VS2017 solution (on Microsoft OneDrive) provides a List of string for found files and a List of string for folder that were denied access too. The ListBox is for visual confirmation. All work is done in a BackGroundWorker so the form will be responsive during a recursive search. Also you see all statistics while running.

    The Skip button will display skipped folders in this case to the Visual Studio output window.


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    Thursday, May 17, 2018 12:39 AM
    Moderator
  • Hi ino_mart,

    >>I've tried this with a Try-function, but this seems not to work as expected.  It seems to run fine at the beginning, but after some "unaccessible" folders, the code quits.

    If you are getting an error when you loop through the files you could throw a try catch around it, log the error and continue processing.

    I find these thread about skipping folders which can't be accessed you can take a look:

    https://stackoverflow.com/questions/4998283/make-directory-getfiles-ignore-protected-folders

    https://stackoverflow.com/questions/172544/ignore-folders-files-when-directory-getfiles-is-denied-access/24440132

    Best Regards,

    Cherry


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, May 17, 2018 6:03 AM
    Moderator
  • Dear
    This is exactly what I needed.  Thanks.

    Thursday, May 17, 2018 6:27 AM