Laden...

StackOverflowException beim rekursiven Verarbeiten von Verzeichnissen mittels Queue

Erstellt von DMsRising vor 9 Jahren Letzter Beitrag vor 9 Jahren 3.392 Views
D
DMsRising Themenstarter:in
3 Beiträge seit 2013
vor 9 Jahren
StackOverflowException beim rekursiven Verarbeiten von Verzeichnissen mittels Queue

Guten Abend,
ich hoffe ich finde in diesem Forum Hilfe: Und zwar rufe ich einen einen Pfad und alle Unterordner rekursiv auf, um alle in den Odernern und Unterordnern Gefundenen Dateien in eine Liste zu packen. Sobald allerdings eine Verknüpfung oder ein vom System geschützer Ordner an der Reihe ist, bricht das Programm mit einer Stackoverflowexception ab.


 private void DataNamesToList()
        {
            _di = new DirectoryInfo(_pathQueue.Dequeue()); //Setzte aktuelles verzeichnis aus queue
            try
            {
                foreach (FileInfo f in _di.GetFiles())  // <== HIER
                {
                    _dateiNamen.Add(f.Name); //füge alle Dateien des Ordners an Liste an
                }
            }
            catch (Exception ex)//wird beim stackoverflow leider nicht abgefangen
            {
                
            }
            if (checkBox_unterordner.Checked) 
            {
                foreach (DirectoryInfo d in _di.GetDirectories()) //füge rekursiv alle unterordner und
                {                                                                   //deren unterordner in die queue
                    _pathQueue.Enqueue(d.FullName);
                }
                if (_pathQueue.Count > 0)
                    DataNamesToList();
            }
        }

Bei Rot markierter Stelle findet sich immer wieder die Meldung> Fehlermeldung:

Eine nicht behandelte Ausnahme des Typs "System.StackOverflowException" ist in mscorlib.dll aufgetreten.

Unter Details findet sich folgendes:> Fehlermeldung:

Ausnahme-Momentaufnahme:
-> System.StackOverflowException {Der Ausdruck kann nicht ausgewertet werden, weil sich der aktuelle Thread in einem Stapelüberlaufzustand befindet.}

Gibt es dazu bereits einen Thread, der dieses Problem behandelt und den ich überlsesen habe, oder kann mir zeigen, wie ich die SOE abfangen, bzw. Systemordner und Verküpfungen von der Suche ausschließen kann?

Viele Grüße

849 Beiträge seit 2006
vor 9 Jahren

Hallo,

du kannst eine SOE nicht abfangen, weil dein Stack halt zu voll ist um noch irgendwas zu machen.

Zu deiner Logik.. Für mich vermischt Du hier zwei verschiedene Methoden an das Problem heran zu gehen. Einmal die Rekursion und einmal Abarbeitung mit einer Queue. Die Queue ist hier denke ich über.


private void DataNamesToList(DirectoryInfo di)
        {
           
            try
            {
               foreach (FileInfo f in _di.GetFiles())
                {
                    _dateiNamen.Add(f.Name); //füge alle Dateien des Ordners an Liste an
                }
            }
            catch (Exception ex)//wird beim stackoverflow leider nicht abgefangen
            {
                //Und hier solltest Du die Exception behandeln!


            }
            if (checkBox_unterordner.Checked)
            {
                foreach (DirectoryInfo d in _di.GetDirectories()) //füge rekursiv alle unterordner und
                {                                                                   //deren unterordner in die queue
                   DataNamesToList(d);
                }
               
                    
            }
        }

allerdings ist mir bis jetzt entgangen warum Du eine SOE bekommst..

L
53 Beiträge seit 2007
vor 9 Jahren
Hinweis von herbivore vor 9 Jahren

Um es vorweg zu nehmen: GetDirectories liefert nur Unterverzeichnisse. Und GetDirectories mit SearchOption.AllDirectories scheitert, wenn auch nur auf ein Verzeichnis keine Zugriffsrechte bestehen. Das gleiche gilt für EnumerateDirectories, zumindest wenn bis zum Verzeichnis mit den fehlenden Zugriffsrechten enumeriert wird.

Hi,

ohne jetzt genau in die Doku geschaut zu haben: Möglicherweise liefert GetDirectories() das aktuelle bzw. das übergeordnete Verzeichnis zurück ("." und "..") - das würde dann den Stacküberlauf erklären.

Unabhängig davon ist die Rekursion hier doch gar nicht notwendig, denn eine Überladung von GetDirectories() kann auch direkt alle Unter-Unterverzeichnisse zurückliefern.

Zuguterletzt würde ich ggf. auf die aktuelleren Versionen EnumerateDirectories zurückgreifen.

Und um noch auf die eigentliche Frage einzugehen: Eine StackOverflow-Exception ist so "schlimm", dass man sie nicht fangen kann. (bzw. nur unter ganz bestimmten Umständen)

Gruß,
Sebastian

D
DMsRising Themenstarter:in
3 Beiträge seit 2013
vor 9 Jahren

warum ist die queue für dich überflüssig?
die benutz ich, um mir die neu auftauchenden Unterordnerpfade zu speichern und systematisch alle aufzunehmen und abzuarbeiten.
@LittelBoy
GetDirectories() wird nicht daran Schuld sein. Wenn ich unterordner aktiviere und ein Verzeichnis ohne Systemordner/verknüpfungen lese, bekomm ich keinen Stackoverflow.

Was genau meinst du mit 'aktuelleren Versionen EnumerateDirectories' ?

49.485 Beiträge seit 2005
vor 9 Jahren

Hallo DMsRising,

deine Verbindung von Rekursion und Queue ist wirklich sehr ungünstig. So wie es jetzt ist, entspricht die Rekursionstiefe der Anzahl der insgesamt gefundenen Verzeichnisse und nicht wie üblich (z.B. in [Snippet] Verzeichnisse und Dateien rekursiv durchlaufen) der Verschachtelungstiefe der Verzeichnisse.

Verwende statt der Rekursion eine Schleife. Dann bist du die SOE los.

EnumerateDirectories ist eine neue Methode, die aber nur dann spürbare Vorteile bringt, wenn man vor hat, die Enumeration abzubrechen, bevor alle Verzeichnisse durchlaufen sind (hast du nicht vor). Oder wenn man Verzeichnisse mit extrem vielen Unterverzeichnissen hat (keine Ahnung ob das bei dir denkbar ist). Ansonsten kann man weiterhin GetDirectories verwenden. GetDirectories hat aus meiner Sicht den Vorteil, dass es das komplette Ergebnis liefert oder gar keins (SecurityException). Bei EnumerateDirectories können Exceptions mitten in der Enumeration auftreten. Und GetDirectories ist sowieso angezeigt, wenn man die Verzeichnisse vor der Verarbeitung sortieren will oder muss. Es kommt also auf die konkrete Situation an, ob die eine oder die andere Methode besser geeignet ist.

Eine mögliche Exception bei GetDirectories solltest du behandeln, so wie du es bei GetFiles auch getan hast.

herbivore

849 Beiträge seit 2006
vor 9 Jahren

Ja, stimmt jetzt habe ich es auch.

Solange in der Queue noch was drin ist, wird die Methode pro Verzeichnis nochmals aufgerufen: Stack++

Und um nochmals zu Fragen: Was spricht dagegen die Queue raus zu schmeissen? Mir würde hier nur Multithreading einfallen, aber in diesem Fall fehlen noch Infos.

49.485 Beiträge seit 2005
vor 9 Jahren

Hallo unconnected,

die Queue muss man nicht zwangsweise rausschmeißen. Es gibt eben die beiden Möglichkeiten. In einer Schleife eine Queue mit den Verzeichnissen zu füllen und sie abzuarbeiten. Oder die Verzeichnisstruktur rekursiv zu durchlaufen. Das hat beides seine Berechtigung. Keines davon ist ausschließlich besser oder ausschließlich schlechter als die jeweils andere Möglichkeit. DMsRising sollte sich nur klar für eines von beidem entscheiden. Der Mix ist es, der die Probleme verursacht.

Mit Rekursion bekommt man standardmäßig eine Tiefensuche. Mit einer Queue bekommt man standardmäßig eine Breitensuche.

herbivore

Gelöschter Account
vor 9 Jahren

Sobald allerdings eine Verknüpfung oder ein vom System geschützer Ordner an der Reihe ist

Das mit der Verknüpfung kann ich nicht beurteilen aber ich würde mich wundern wenn System.File.IO ein .lnk automatisch verarbeitet. Ich will es aber auch nicht ausschliessen, obwohl ich mir doch recht sicher bin recht zu haben.

Der Zugriff auf einen Systemordner ist nicht anders als der Zugriff auf anderer Ordner ausser das man eine Security Exception erwarten muss(wie bei allen anderen Ordnern eigentlich auch)

Insofern ist deine Beobachtung und dein Folgeschluss falsch. Der System Ordner und wahrscheinlich auch die Verknüpfung hat nix damit zu tun das du eine SOE Exception bekommst. Du rufst in einem 2. Codeblock nach try/catch ja nochmal GetDirectory auf, warum und woher weisst du das die Exception nicht aus dem Codeblock stammt, speziell aus deinen eigenen Methoden pathQueue(was immer das ist) oder DataNamesToList . Dein try/catch block mit GetFiles() sollte aus meiner Sicht keine SOE Exception werfen ausser dein Dateisystem ist so überfüllt das er den zulässigen Stack Memory in .Net überschreitet. Anders gesagt ich habe nicht den Eindruck das die SOE Exception vom FileSystem kommt, jedenfalls sehe ich darauf keinen Hinweis.

49.485 Beiträge seit 2005
vor 9 Jahren

Hallo Sebastian.Lange,

richtig, Verknüpfungen im Sinne von LNK-Dateien auf Ordner wird nicht automatisch gefolgt. Die werden von GetFiles geliefert, nicht von GetDirectories. Aber es gibt andere Arten von Verknüpfungen, z.B. Hardlinks oder Junktions, die von GetDirectories geliefert werden, als wären sie normale Verzeichnisse. Siehe dazu auch die Diskussion in [Snippet] Verzeichnisse und Dateien rekursiv durchlaufen ff bis zum Beitrag von winSharp93 [Snippet] Verzeichnisse und Dateien rekursiv durchlaufen, der eine Lösungsmöglichkeit aufzeigt. Insofern könnte durch eine derartige Verknüpfung durchaus eine Endlosrekursion entstehen. Ich bin allerdings deiner Meinung, dass dies hier eher trotzdem nicht der Fall ist, sondern die Ursache in der Art der Rekursion liegt, die ich weiter oben beschrieben habe.

herbivore