none
GetFiles mit Subdirectories liefert keine Werte RRS feed

  • Frage

  • Hallo zusammen,

    ich bin noch recht neu in .NET (war bsiher nur in VBA unterwegs) und bin grad ein wenig am rumtesten. Nun habe ich in meiner WPF-Applikation ein kleines Problem:

    Ich habe dort eine Klasse, welche mir Dateien aus einem Pfad (=Laufwerk) zurückgeben soll. Dies funktioniert auch aber NUR mit "SearchTopLevelOnly", das ganze mit "SearchAllSubDirectories" funktioniert leider nicht -> bekomme nichts zurück. Kenn jemand zufällig das Problem bzw. eine Abhilfe ?

    Vielen Dank.

    Hier noch der Code, falls es weiter hilft (als pPath wird "E:\" übergeben:

        Public Function getFiles(ByVal pPath As String) As Collection
            Dim colResult As New Collection
    
            For Each file In My.Computer.FileSystem.GetFiles(pPath, FileIO.SearchOption.SearchAllSubDirectories, "*.txt")
                colResult.Add(file)
            Next
            Return colResult
        End Function
    Samstag, 8. August 2009 23:32

Antworten

  • Hallo,

    ich blende mich mal in eure Diskussion ein.

    Das Problem einer rekursiven Dateisuche ist, das man nicht immer auf alle Verzeichnisse Zugriff hat. Auf das "System Volume Information" Verzeichnis, das die Wiederherstellungsinformationen des Betriebssystems enthält, hat unter normalen Umständen nicht einmal ein Administrator Zugriff.

    Weder My.Computer.FileSystem.GetFiles - das sowieso überflüssiger als ein Kropf ist - noch System.IO.Directory.GetFiles fangen das ab, sondern reichen die UnAuthorizedAccessException weiter. Mit dem Endresultat, dass man kein Ergebnis bekommt.

    In der MS KB gibt es einen Artikel SO WIRD'S GEMACHT: Rekursives Durchsuchen von Verzeichnissen in Visual Basic .NET, der eine alternative Lösung zeigt, aber IMHO es zuweit mit dem Schlucken von Ausnahmen treibt.

    Eine alternative Variante, die nach mehreren Dateimustern suchen kann, das Ergebnis am Ende sortiert und die Rekursion durch einen Stack ersetzt:

    Public Class FileHelper
        ''' <summary>
        ''' Erstellt eine Dateiliste rekursiv.
        ''' </summary>
        ''' <remarks>
        ''' Es kann nach mehreren Mustern gesucht werden, die durch ";" getrennt werden.
        ''' Dateien und Verzeichnisse auf die kein Zugriff besteht werden ausgelassen.
        ''' </remarks>
        ''' <param name="path">Der Ausgangspfad.</param>
        ''' <param name="searchPatterns">Eine Liste von Suchmustern</param>
        ''' <returns>eine List&lt;String&gt;</returns>
        Public Shared Function FindFilesRecursive( _
            ByVal path As String, _
            ByVal searchPatterns As String) As List(Of String)
    
            If path Is Nothing Then
                Throw New ArgumentNullException("path")
            End If
    
            path = path.Trim()
            If path.Length = 0 Then
                Throw New ArgumentException("path")
            End If
            If String.IsNullOrEmpty(searchPatterns) Then
                Throw New ArgumentNullException("searchPatterns")
            End If
    
            ' Anfangspfad vorgeben (hier mögliche Ausnahme)
            path = System.IO.Path.GetFullPath(path)
    
            Dim fileList As New List(Of String)
    
            ' Trennen der Suchmuster
            Dim searchPatternList As New List(Of String)
            For Each pattern As String In searchPatterns.Split(";"c)
                pattern = pattern.Trim()
                If pattern.Length > 0 Then
                    searchPatternList.Add(pattern)
                End If
            Next
    
            If searchPatternList.Count = 0 Then
                Return fileList
            End If
    
            Dim directoryStack As New Stack(Of String)
            directoryStack.Push(path)
            ' Verzeichnisse rekursiv (via Stack) durchlaufen
            Do While directoryStack.Count > 0
                Dim directory As String = directoryStack.Pop()
    
                Try
                    ' Durchlaufen aller Suchmuster
                    For Each pattern As String In searchPatternList
                        ' ... und zur Dateiliste hinzufügen
                        fileList.AddRange(System.IO.Directory.GetFiles(directory, pattern))
                    Next
                Catch ex As UnauthorizedAccessException
                    System.Diagnostics.Debug.WriteLine("No File Access " & directory)
                    ' Kein Zugriff
                End Try
    
                ' Einfügen der Unterverzeichnisse in den Stack
                Try
                    For Each subDirectory As String In System.IO.Directory.GetDirectories(directory)
                        directoryStack.Push(subDirectory)
                    Next
                Catch ex As UnauthorizedAccessException
                    ' Kein Zugriff
                    System.Diagnostics.Debug.WriteLine("No Directory Access " & directory)
                End Try
            Loop
    
            ' Sortiert die Dateinamen
            fileList.Sort(StringComparer.OrdinalIgnoreCase)
            Return fileList
        End Function
    
        ''' <summary>
        ''' Kleiner Test zu FindFilesRecursive
        ''' </summary>
        <Conditional("Debug")> _
        Friend Shared Sub FindFileRecursiveTest()
            Dim path As String = "E:"
            'Dim searchPatterns As String = "*.wav"
            Dim searchPatterns As String = "*.mp3;*.wav;*.wmv;*.wma"
    
            Dim fileList As List(Of String) = FileHelper.FindFilesRecursive(path, searchPatterns)
            Dim builder As New System.Text.StringBuilder(128)
            For Each name As String In fileList
                builder.AppendLine(name)
            Next
    
            System.IO.File.WriteAllText("F:\fileslist.txt", builder.ToString())
        End Sub
    End Class

    Gruß Elmar

    Sonntag, 9. August 2009 17:15
    Beantworter

Alle Antworten

  • Hallo,

    versuch es mal mit Typangabe:

    For Each file As String  In My.Computer.FileSystem.GetFiles(pPath, FileIO.SearchOption.SearchAllSubDirectories, "*.txt")
                colResult.Add(file)
    Next


    Dann sollte es auch gehen.

    Schöne Grüße
    Oliver
    Sonntag, 9. August 2009 12:18
  • das wars leider nicht.

    Ich poste mal den ganzen Code rein, vielleicht stimmt der Aufruf nicht (was ich aber eig. nicht glaube):

    Class Window1 
        Private Sub Window1_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
            Dim colFound As New Collection
            Dim objData As New DataReader
    
            colFound = objData.getFiles("E:\")
    
            For Each foundFile As String In colFound
                MessageBox.Show(foundFile)
            Next
        End Sub
    End Class
    

    Public Class DataReader
        Public Function getFiles(ByVal pPath As String) As Collection
            Dim colResult As New Collection
    
            For Each file As String In My.Computer.FileSystem.GetFiles(pPath, FileIO.SearchOption.SearchAllSubDirectories, "*.mp3")
                colResult.Add(file)
            Next
            Return colResult
        End Function
    End Class
    Sonntag, 9. August 2009 12:30
  • Hallo,

    wenn ich das richtig sehe hast Du einen Dateifilter für Mpeg-Files. Hast Du den Files von diesen Dateityp auf der E:\ - Partition? Wenn nicht würdest Du in eine nicht abgefangene Exception laufen und bekommst dann auch kein Ergebnis.

    Ich werde Deinen Code gleich testen und melde mich wieder.

    Schöne Grüße
    Oliver
    Sonntag, 9. August 2009 13:13
  • Ist zwar *.mp3 aber ja: Das E-Laufwerk ist mein Laufwerk mit meinen Songs, da hats mehr als genug.
    Und wie gesagt, wenn ich nur "TopLevel" suche, dann zeigt er mir alle an - mit "SubDirectories" halt nichts..
    Sonntag, 9. August 2009 13:17
  • Hallo,

    die Zeile: colFound = objData.getFiles("E:\")  funktioniert nicht.

    Wenn ich z.B.  colFound = objData.getFiles("E:\Music\") eingebe, bekomme ich ein Ergebnis.

    Schöne Grüße
    Oliver
    Sonntag, 9. August 2009 13:40
  • Danke.

    Das heißt also, Laufwerke direkt lassen sich damit nicht durchsuchen - Dabei hab ich das aber vor.
    Dann muss ich mal schauen, wie ich ganze Laufwerke durchsuchen kann.
    Sonntag, 9. August 2009 13:44
  • Hallo,

    jetzt ist die NET BCL angesagt. Der Namespace lautet System.IO. Die entsprechenden Klassen sind System.IO.DirectoryInfo und System.IO.FileInfo. Schau es Dir in der MSDN Doku mal an.

    Schöne Grüße
    Oliver
    Sonntag, 9. August 2009 13:52
  • Hab den Fehler wahrscheinlich gefunden:

    Habe das ganze jetzt in ein try gepackt und bekomme folgendes:


    Der Zugiff auf den Pad "E:\RECYCLER\hier steht ein file" wurde verweigert.

    - Das heißt also, er durchläuft auch die versteckten- und Systemordner ?
    Sonntag, 9. August 2009 13:58
  • Daran hätte ich eigentlich denken müssen. Ja, für My.Computer.FileSystem sind Systemverzeichnisse auch gültige SubDirectories. Das ist dann eine Zugriffsverletzung gibt, ist logisch.

    Schöne Grüße
    Oliver
    Sonntag, 9. August 2009 14:05
  • Problem ist nur: Mit For Each file As String In System.IO.Directory.GetFiles(pPath, "*mp3", IO.SearchOption.AllDirectories) bekomm ich den Fehler, dass er auf die "System Volume Information" nicht zugreifen kann.

    Vielleicht find ich ja noch etwas, womit er nicht auf die ganzen versteckten Files und Ordner zugreifen will.
    Sonntag, 9. August 2009 14:16
  • Hallo,

    das Grundgerüst dafür sieht so aus:

    Try
    
    Dim dir As DirectoryInfo = New DirectoryInfo("E:\")
    Dim dirs As DirectoryInfo() = dir.GetDirectories()
    Dim di As DirectoryInfo
    For Each di In dirs
      di.GetFiles("*.mp3")
    Next
         
    Catch e As SecurityException
    End Try
    Du mußt Deinen Code zur Verarbeitung der Informationen (z.B. Ausgabe in eine ListBox, etc) noch eingeben.

    Schöne Grüße
    Oliver
    Sonntag, 9. August 2009 14:54
  • Hallo,

    das Grundgerüst dafür sieht so aus:

    ...
    
    
    
    Du mußt Deinen Code zur Verarbeitung der Informationen (z.B. Ausgabe in eine ListBox, etc) noch eingeben.

    Schöne Grüße
    Oliver

    Das gibt leider auch wieder den Fehler, dass auf "System Volume Information" nicht zugegriffen werden kann
    • Bearbeitet R.ST Sonntag, 9. August 2009 15:17
    Sonntag, 9. August 2009 15:16
  • Hallo,

    ich hab den Code gerade getestet. Mach bitte aus dem Catch e ein Catch ex. Das Programm kommt mit der Variable e nicht zu recht. Außerdem müßte es heissen Security.SecurityException oder Du schreibts eine Imports - Directive für System.Security. Das sollte das Problem mit dem Mülleimer usw. lösen.

    Jetzt habe ich noch ein weiteres Problem gefunden. Wenn ein SubDirectory unter E:\ eigene SubDirectories hat, so werden diese im Programmdurchlauf ignoriert. Dateien die beispielsweise im Verzeichnis E:\music liegen werden aber fehlerfrei angezeigt, E:\music\film\ erscheint nicht in der Ausgabe.

    Hier nocheinmal der Code:

    Imports System.IO
    Imports System.Security
    
    Public Class Form1
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Try
    
                Dim dir As DirectoryInfo = New DirectoryInfo("E:\")
                Dim dirs As DirectoryInfo() = dir.GetDirectories()
                Dim di As DirectoryInfo
                For Each di In dirs
                    di.GetFiles("*.mp3")
                    Dim fn As FileInfo
                    Dim fname As String
                    For Each fn In di.GetFiles("*.mp3")
                        fname = fn.Name
                        MessageBox.Show(fname)
    
                    Next
    
                Next
    
            Catch ex As SecurityException
            End Try
    
    
        End Sub
    End Class

    Schöne Grüße

    Oliver

    Sonntag, 9. August 2009 15:52
  • Hallo,

    ich blende mich mal in eure Diskussion ein.

    Das Problem einer rekursiven Dateisuche ist, das man nicht immer auf alle Verzeichnisse Zugriff hat. Auf das "System Volume Information" Verzeichnis, das die Wiederherstellungsinformationen des Betriebssystems enthält, hat unter normalen Umständen nicht einmal ein Administrator Zugriff.

    Weder My.Computer.FileSystem.GetFiles - das sowieso überflüssiger als ein Kropf ist - noch System.IO.Directory.GetFiles fangen das ab, sondern reichen die UnAuthorizedAccessException weiter. Mit dem Endresultat, dass man kein Ergebnis bekommt.

    In der MS KB gibt es einen Artikel SO WIRD'S GEMACHT: Rekursives Durchsuchen von Verzeichnissen in Visual Basic .NET, der eine alternative Lösung zeigt, aber IMHO es zuweit mit dem Schlucken von Ausnahmen treibt.

    Eine alternative Variante, die nach mehreren Dateimustern suchen kann, das Ergebnis am Ende sortiert und die Rekursion durch einen Stack ersetzt:

    Public Class FileHelper
        ''' <summary>
        ''' Erstellt eine Dateiliste rekursiv.
        ''' </summary>
        ''' <remarks>
        ''' Es kann nach mehreren Mustern gesucht werden, die durch ";" getrennt werden.
        ''' Dateien und Verzeichnisse auf die kein Zugriff besteht werden ausgelassen.
        ''' </remarks>
        ''' <param name="path">Der Ausgangspfad.</param>
        ''' <param name="searchPatterns">Eine Liste von Suchmustern</param>
        ''' <returns>eine List&lt;String&gt;</returns>
        Public Shared Function FindFilesRecursive( _
            ByVal path As String, _
            ByVal searchPatterns As String) As List(Of String)
    
            If path Is Nothing Then
                Throw New ArgumentNullException("path")
            End If
    
            path = path.Trim()
            If path.Length = 0 Then
                Throw New ArgumentException("path")
            End If
            If String.IsNullOrEmpty(searchPatterns) Then
                Throw New ArgumentNullException("searchPatterns")
            End If
    
            ' Anfangspfad vorgeben (hier mögliche Ausnahme)
            path = System.IO.Path.GetFullPath(path)
    
            Dim fileList As New List(Of String)
    
            ' Trennen der Suchmuster
            Dim searchPatternList As New List(Of String)
            For Each pattern As String In searchPatterns.Split(";"c)
                pattern = pattern.Trim()
                If pattern.Length > 0 Then
                    searchPatternList.Add(pattern)
                End If
            Next
    
            If searchPatternList.Count = 0 Then
                Return fileList
            End If
    
            Dim directoryStack As New Stack(Of String)
            directoryStack.Push(path)
            ' Verzeichnisse rekursiv (via Stack) durchlaufen
            Do While directoryStack.Count > 0
                Dim directory As String = directoryStack.Pop()
    
                Try
                    ' Durchlaufen aller Suchmuster
                    For Each pattern As String In searchPatternList
                        ' ... und zur Dateiliste hinzufügen
                        fileList.AddRange(System.IO.Directory.GetFiles(directory, pattern))
                    Next
                Catch ex As UnauthorizedAccessException
                    System.Diagnostics.Debug.WriteLine("No File Access " & directory)
                    ' Kein Zugriff
                End Try
    
                ' Einfügen der Unterverzeichnisse in den Stack
                Try
                    For Each subDirectory As String In System.IO.Directory.GetDirectories(directory)
                        directoryStack.Push(subDirectory)
                    Next
                Catch ex As UnauthorizedAccessException
                    ' Kein Zugriff
                    System.Diagnostics.Debug.WriteLine("No Directory Access " & directory)
                End Try
            Loop
    
            ' Sortiert die Dateinamen
            fileList.Sort(StringComparer.OrdinalIgnoreCase)
            Return fileList
        End Function
    
        ''' <summary>
        ''' Kleiner Test zu FindFilesRecursive
        ''' </summary>
        <Conditional("Debug")> _
        Friend Shared Sub FindFileRecursiveTest()
            Dim path As String = "E:"
            'Dim searchPatterns As String = "*.wav"
            Dim searchPatterns As String = "*.mp3;*.wav;*.wmv;*.wma"
    
            Dim fileList As List(Of String) = FileHelper.FindFilesRecursive(path, searchPatterns)
            Dim builder As New System.Text.StringBuilder(128)
            For Each name As String In fileList
                builder.AppendLine(name)
            Next
    
            System.IO.File.WriteAllText("F:\fileslist.txt", builder.ToString())
        End Sub
    End Class

    Gruß Elmar

    Sonntag, 9. August 2009 17:15
    Beantworter
  • Hallo R.ST,

    Hat Dir die Antwort weiter geholfen?

    Grüße,
    Robert

    Freitag, 21. August 2009 14:32
    Moderator
  • Hallo R.ST,

    Ich gehe davon aus, dass die Antwort Dir weitergeholfen hat.

    Grüße,
    Robert

    Dienstag, 25. August 2009 19:24
    Moderator