Harsha
Harsha

Reputation: 571

How to iterate through files and skip the ones to which I don't have access

I want to get all files in a directory, so I have used For Each loop. but I got this error and stopped the loop.

System.UnauthorizedAccessException: 'Access to the path 'G:\$RECYCLE.BIN\S-1-5-18' is denied.'

The loop cannot access some of the files because of file permissions. I want to by-pass those files and move to the next file.

how can I do this,

Try

    For Each filename As String In Directory.GetFiles(dir_path, pattern, sub_directory)
        Console.WriteLine(filename.ToString)
    Next filename

Catch ex As Exception

End Try

Upvotes: 2

Views: 570

Answers (1)

jmcilhinney
jmcilhinney

Reputation: 54457

The loop is irrelevant. It's the call to GetFiles that is the problem. There is no way to call GetFiles with the recursive option and simply ignore inaccessible folders. You can only use that method when you know you can access every subfolder. Otherwise, you need to write your own recursive file search and explicitly catch those exceptions and ignore them. There are lots of examples of that on the web.

It should be noted that GetFiles does the entire search first, creates an array containing all the file paths and returns it, so your loop can't even begin until that's done. Even if this could work, it would still generally be preferable to call EnumerateFiles if you want to loop through the file paths on the spot. That's because EnumerateFiles is an iterator, basically returning the file paths one by one. That means that, for instance, you can break out of the loop if a particular condition is met without completing the entire search. EnumerateFiles will still throw an exception if it finds an inaccessible folder though, so it won't help here. If you do write your own method though, it would be nice to write an iterator if you plan to search big folders or you might not need to use all results.

EDIT:

Here's my home-spun versions. The first one does all the work first while the second is an iterator. Note that you may be able to make the first one more efficient by using a single external list to store all the file paths in rather than creating a new one in every recursive call.

Public Function GetFilesRecursively(path As String, searchPattern As String) As String()
    Dim filePaths As New List(Of String)(Directory.GetFiles(path, searchPattern))

    For Each folderPath In Directory.GetDirectories(path)
        Try
            filePaths.AddRange(GetFilesRecursively(folderPath, searchPattern))
        Catch ex As UnauthorizedAccessException
            'Ignore inaccessible folders
        End Try
    Next

    Return filePaths.ToArray()
End Function

Public Iterator Function EnumerateFilesRecursively(path As String, searchPattern As String) As IEnumerable(Of String)
    For Each filePath In Directory.EnumerateFiles(path, searchPattern)
        Yield filePath
    Next

    For Each folderPath In Directory.EnumerateDirectories(path)
        Try
            For Each filePath In EnumerateFilesRecursively(folderPath, searchPattern)
                Yield filePath
            Next
        Catch ex As UnauthorizedAccessException
            'Ignore inaccessible folders
        End Try
    Next
End Function

Upvotes: 3

Related Questions