FileSystem.GetFiles () + UnauthorizedAccessException ошибка? - PullRequest
0 голосов
/ 15 марта 2010

Это похоже на FileSystem.GetFiles () не может восстановиться из исключения UnauthorizedAccessException, которое .Net срабатывает при попытке доступа к каталогу с ограничениями.

В этом случае означает ли это, что этот класс / метод бесполезен при сканировании всего диска, и мне следует использовать другое решение (в этом случае: какое?)?

Вот код, показывающий проблему:

Private Sub bgrLongProcess_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgrLongProcess.DoWork
    Dim drive As DriveInfo
    Dim filelist As Collections.ObjectModel.ReadOnlyCollection(Of String)
    Dim filepath As String

    'Scan all fixed-drives for MyFiles.*
    For Each drive In DriveInfo.GetDrives()
        If drive.DriveType = DriveType.Fixed Then
            Try
                'How to handle "Access to the path 'C:\System Volume Information' is denied." error?
                filelist = My.Computer.FileSystem.GetFiles(drive.ToString, FileIO.SearchOption.SearchAllSubDirectories, "MyFiles.*")
                For Each filepath In filelist
                  DataGridView1.Rows.Add(filepath.ToString, "temp")
                  'Trigger ProgressChanged() event
                  bgrLongProcess.ReportProgress(0, filepath)
                Next filepath
            Catch Ex As UnauthorizedAccessException
                'How to ignore this directory and move on?
            End Try
        End If
    Next drive
End Sub

Спасибо.


Редактировать: А как насчет использования Try / Catch только для того, чтобы GetFiles () заполнил массив, проигнорировал исключение и просто возобновил?

Private Sub bgrLongProcess_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgrLongProcess.DoWork
    'Do lengthy stuff here
    Dim filelist As Collections.ObjectModel.ReadOnlyCollection(Of String)
    Dim filepath As String

    filelist = Nothing
    Try
        filelist = My.Computer.FileSystem.GetFiles("C:\", FileIO.SearchOption.SearchAllSubDirectories, "MyFiles.*")
    Catch ex As UnauthorizedAccessException
        'How to just ignore this off-limit directory and resume searching?
    End Try

    'Object reference not set to an instance of an object
    For Each filepath In filelist
        bgrLongProcess.ReportProgress(0, filepath)
    Next filepath
End Sub

Ответы [ 3 ]

1 голос
/ 15 марта 2010

Поместите оператор try catch в цикл For each filepate in filelist. Потому что сейчас, когда вы ловите UnauthorizedAccessException, вы пропускаете остальные элементы filelist.

Редактировать

Вы правы. Попытка перехвата обходится дорого, когда выдается исключение, и обычно вы хотите попытаться обнаружить эту ситуацию до того, как выдается исключение. Один из способов сделать это в этой ситуации - проверить доступ к файлу, прежде чем что-либо делать с ним.

Для каталогов существует эта функция GetAccessControl . Там есть аналогичная функция для файлов.

Возможно, вам придется прервать функцию GetFiles, чтобы изначально получать только каталоги, а затем рекурсивно перебирать каждый каталог, вызывая GetAccessControl для каждого каталога и файла.

0 голосов
/ 15 декабря 2015

Я использую следующие функции для поиска определенных файлов на всех дисках, расположенных в системе, и он не прерывается, когда «GetFiles» срабатывает. Это делается путем выполнения поиска только верхнего уровня с помощью «GetDirectories», который даст вам список каталогов базового уровня, и, если он не выбрасывает исключение, выполняется поиск «GetFiles» по всем подкаталогам этого каталога, если это исключение затем нажмите, затем каталог «GetDirectories», и процесс продолжается. После каждого успешного поиска, выполненного GetFiles, каталоги, содержащие файлы, которые были найдены, сохраняются в списке. После того как все существующие диски, расположенные в системе, были найдены, основная функция завершает свою работу, возвращая данные, добавленные в список.

Public Function Left(ByVal TextString As String, ByVal LocateString As String) As String
    Try
        Left = Microsoft.VisualBasic.Left(TextString, InStrRev(TextString, LocateString) - 1)
    Catch ex As Exception
        Left = TextString
    End Try
End Function

Public Function GetExistingDrives() As List(Of String)
    Dim LocatedDrives As New List(Of String), DriveInformation As System.IO.DriveInfo() = System.IO.DriveInfo.GetDrives
    For Each FoundDrive As System.IO.DriveInfo In DriveInformation
        Try
            LocatedDrives.Add(UCase(Left(FoundDrive.Name, "\")))
        Catch ex As Exception
        End Try
    Next
    GetExistingDrives = LocatedDrives
End Function

Public Function LocateFiles(ByVal ParamArray SearchPattern As String()) As List(Of String)
    Dim LocatedDirectoriesList As New List(Of String), LocatedFilenameList As System.Collections.ObjectModel.ReadOnlyCollection(Of String)
    For Each DriveLetter In GetExistingDrives()
        Try
            For Each SearchDirectory As String In My.Computer.FileSystem.GetDirectories(DriveLetter, FileIO.SearchOption.SearchTopLevelOnly)
                Try
                    LocatedFilenameList = My.Computer.FileSystem.GetFiles(SearchDirectory, FileIO.SearchOption.SearchAllSubDirectories, SearchPattern)
                Catch ex As Exception
                End Try
                If (LocatedFilenameList.Count <> 0) Then
                    For Each LocatedFilename As String In LocatedFilenameList
                        Dim LocatedDirectory As String = Left(LocatedFilename, "\")
                        If (LocatedDirectoriesList.IndexOf(LocatedDirectory) = -1) Then LocatedDirectoriesList.Add(LocatedDirectory)
                    Next
                End If
            Next
        Catch ex As Exception
        End Try
    Next
    LocateFiles = LocatedDirectoriesList
End Function
0 голосов
/ 16 марта 2010

Для интересующихся я нашел следующее рабочее решение:

http://dotnetperls.com/recursive-file-directory-vbnet

Если вы хотите отфильтровать поиск по заданному типу файлов (например, «MyFiles. *»), Измените

Public Shared Function GetFilesRecursive(ByVal initial As String, ByVal extension As String) As List(Of String)

... так вы можете назвать это так:

Dim list As List(Of String) = FileHelper.GetFilesRecursive("C:\", "MyFiles.*")
...