BigBastis Blog

VB: Ordnerstrukturen einlesen Teil 2

Introduction

user

Sebastian Gross

Sebastian Gross arbeitet in Bielefeld als Softwareentwickler für .NET und Java im Bereich Web.Als Fan der .NET-Plattform lässt er sich kein Userguppen Treffen und Community Event im Raum OWL entgehen.Dabei hat er eine besondere Vorliebe für das ASP.NET MVC Framework und für das Test Driven Development (TDD) entwickelt.


LATEST POSTS

Handling too long scrollspy menus 10th June, 2015

Java: Create ZIP archive 23rd March, 2015

.NET

VB: Ordnerstrukturen einlesen Teil 2

Posted on .

In dem ersten Teil dieses Tutorials haben wir eine Ordnerstruktur bzw. einen Ordnerbaum in eine Treeview mit Hilfe einer Rekursiven Methode in eine TreeView geladen. Dabei haben wir festgestellt, dass das wunderbar funktioniert, aber sehr lange dauert, und den Anschein erwecken könnte, dass das Programm abgestürzt ist, da es nicht mehr auf Eingaben reagiert!

Am Ende des ersten Teils haben wir uns also die Frage gestellt, wie macht es der Windows Explorer, dass er die Ordnerstrukturen so schnell einließt? Um diese Frage zu beantworten muss man den Windows Explorer (ab nun WE) mal etwas genauer beobachten.

Ich wette ihr kennt alle folgende Situation. Ihr startet den WE und seht eure Ordner meißt sofort, nun öffnet ihr einen Unterordner (von dem Ihr wisst, dass dieser viele Daten enthält) und müsst feststellen, dass der WE nun einen Moment braucht um dessen Inhalt anzuzeigen!

Ein weiteres Beispiel ist, dass der WE manchmal das „plus“-Zeichen für Ordner-Aufklappen anzeigt, aber wenn man darauf klickt, verschwindet dieses „plus“-Zeichen wieder. Was daran liegt, das der WE nun feststellt (allso erst beim Klicken), dass der Ordner garkeine weiteren Unterordner hat!

Diese „Phänomene“, besonders das erste, tauchen sehr oft nach dem frischen Start von Windows auf!

Was kann man also aus dieser Beobachtung schließen? Ganz einfach, dass der WE nicht gleich den Ganzen Ordnerpfad lädt. Denn würde er das tun wäre er viel langsamer, zb so wie unser Programm aus Teil 1!

Wenn man über dieses Vorgehen nachdenkt wird man feststellen, dass es genial ist! Warum soll ich alle Ordner einlesen, was zeitlastig ist, wenn ich nur einen Ordner einlesen kann und dann erstmal abwarte, wohin der Benutzer dann will um diesen Ordner dann erst zu laden.

Oder auch eine zweite Variante ist möglich. Man lädt erstmal den Ersten Ordner ein und zeigt diesen dem Benutzer an. Dadurch kann der Benutzer schon mal sein weiteres Vorgehen planen. Und während der Benutzer nachdenkt welchen Ordner er als nächstes öffnen soll lädt das Programm im Hintergrund die restliche Ordnerstruktur nach.

In diesem Beispiel möchte ich auf diese (zweite) Variante eingehen und unser Beispiel aus Teil 1 so erweitern, dass es genauso arbeitet! (Ihr könnt als Vorlage den Code aus Teil 1 verwenden)

Also unser Vorgehen nochmal zusammengefasst:

1. Den vom Benutzer gewählten Ordner einlesen (nur erste Ebene!)

2. Die eingelesene Ebene anzeigen

3. Im Hintergrund die restlichen Unterordner nachladen

Schritt 3 ist hierbei der komplizierteste, denn wir müssen dafür sorgen, dass der Benutzer Eingaben tätigen kann, aber das Programm weiter die Ordner nachlädt, also zwei dinge gleichzeitig tun! – Wie machen wir das?

Dieses Problem werden wir lösen, in dem wir den Code für Schritt 3 in einen separaten Thread auslagern der läuft dann neben dem Form1-Thread, der die Benutzereingaben verarbeitet!

Das heißt wir müssen unser altes Programm um zwei neue Funktionen erweitern, nämlich um die Funktion die ersteinmal Schritt 1 & 2 erledigt und dann die zweite neue Funktion in einem neuen Thread startet damit diese dann Schritt 3 erledigen kann!

Hier die neuen Funktionen:

    Sub getAllSubFolders()
        'Alle Ordner aus dem gewählten Pfad auslesen
        For Each s As IO.DirectoryInfo In _
          New IO.DirectoryInfo(path).GetDirectories
            t.Nodes.Add(s.Name)
        Next
        'Einen neuen Thread erstellen der
        'alle restichen Verzeichnisse ausließt
        Dim a As New Threading.Thread(AddressOf startTheSubDir)
        a.Start()
    End Sub

    Sub startTheSubDir()
        For Each tn As TreeNode In t.Nodes
            Try
                'nun lassen wir den Thread die Unterordner
                'von allen Verzeichnissen in der Root-Note t
                'einlesen und zu t hinzufügen
                TreeView1.Invoke(New getFoldersFromPathDel _
                  (AddressOf getFoldersFromPath), _
                    New Object() {tn.FullPath, tn})
            Catch ex As Exception
                'Es kann die UnauthorizedAccessException Auftreten!
                'Diese wird hier abgefangen soadass nur
                'Ordner eingelesen werden die für das
                'Programm freigegeben sind (nur Vista)
                'alle Fehler speichern
                errors = errors & vbNewLine & ex.Message
            End Try
        Next
        MessageBox.Show(errors)
    End Sub

    'Diese Funktion ist der Delegate Aufruf von getFoldersFromPath
    'Diese Wird benötigt um auf den Inhalt von TreeView1 zuzugreifen
    'Da die TreeView1 von einem anderen Thread erstellt wurde kann nur dieser
    'Darauf zugreifen! Durch die Invoke-Methode können wir dieses Problem umgehen
    Public Delegate Function getFoldersFromPathDel _
      (ByVal start As String, ByVal tv As TreeNode)

Wie man sieht wird ersteinmal die Funktion getAllSubFolders aufgerufen, die dann den ersten Ordner einließt und dann einen neuen Thread mit der Funktion startTheSubDir startet.

Noch bevor der neue Thread gestartet ist sieht der Benutzer seinen gewählten Ordner und dessen Unterordner, die er aber noch nicht erweitern kann. Nun im Hintergrund werden die einzelnen Ordner nachgeladen und die einzelnen „plus“-Zeichen tauchen an den Ordnern auf, die erweiterbar sind!

Dafür sorgt der Thread der nebenbei läuft, und über die Delegierte Funktion getFoldersFromPathDel die rekursive Funktion aus Teil 1 aufruft!

An dieser Stelle ist es wichtig zu wissen, warum man hier delegieren muss. In VB ist es so ein Steuerelement (zb. eine TreeView) kann nur von dem Thread bedient werden, der dieses auch erstellt hat. Will man nun aber aus einem anderen Thread auf dieses Steuerelement zugreifen muss man dieses ersteinmal mit der Funktion bekannt machen! Das ist was Delegate macht!

Man merkt sofort, dass diesmal das Programm sehr viel schneller den selben Ordnerpfad einlesen kann als noch aus Teil 1. Man hat sofort etwas womit man weiterarbeiten kann, ohne ersteinmal warten zu müssen, bis alles fertig ist!

Dieses Vorgehen ist aber immernoch nicht das optimalste! Besser wäre es doch für jeden Ordnerpfad der in Schritt 1 eingelesen wird einen eigenen Thread zu starten der dann nur die Unterordner zu dem einen Ordner einließt! Denn so wie es nun hier ist muss der eine Thread die ganze Arbeit machen und ist unterm Strich nur wenig schneller als der aus Teil 1!

Da dieser Beitrag sonst zu lang geworden wäre werde ich wohl doch noch einen Teil 3 machen wo ich auch auf die eben beschriebene Methode eingehe! Wenn bei euch Interesse besteht!

Bitte teilt mir auch eure Meinung & Vorschläge per Comment oder Mail mit.

Dieses Beispiel herunterladen: Download

profile

Sebastian Gross

http://www.bigbasti.com

Sebastian Gross arbeitet in Bielefeld als Softwareentwickler für .NET und Java im Bereich Web.Als Fan der .NET-Plattform lässt er sich kein Userguppen Treffen und Community Event im Raum OWL entgehen.Dabei hat er eine besondere Vorliebe für das ASP.NET MVC Framework und für das Test Driven Development (TDD) entwickelt.

Comments
user

Author Ploetzeneder Andreas

Posted at 10:52 19. August 2009.

VB bietet hier tolle moeglichkeiten. Ich habe auf meiner Website uach einige Beispiele Hierzu. Ueber einen Linktausch wuerde ich mich sehr freuen

user

Author Freddy

Posted at 07:44 21. Mai 2010.

heyhey
sehr hilfreich und informativ!
das hilft mir im umgang mit WE weiter

user

Author Markus Autoteile

Posted at 12:16 19. Juli 2010.

Hallo, Ich moechte mich meinem Vorredner anschließen. Stimme da zu 100 % zu, außerdem finde ich deinen Blog sehr informativ, also weiter so habe den Blog mal gebookmakrt. Gruß M.Reifen ( Der Autoteile sein tägliches Brot nennt )

Kommentar verfassen

View Comments (3) ...
Navigation