.
Anmeldung | Registrieren | Hilfe
in Suchen

Schnelles einlesen einer Ordnerstruktur mit allen Dateien

Letzter Beitrag 18. Jul 2016 12:29 von gfoidl. 11 Antworten.
Seite 1 von 1 (12 Treffer)
Beiträge sortieren: Zurück Weiter
  • 16. Nov 2008 10:55

    • snaut
    • Top 500 Mitwirkender
    • Registriert am 16. Nov 2008
    • Beiträge 4
    • Punkte 65

    Schnelles einlesen einer Ordnerstruktur mit allen Dateien

    Hallo,

    bei einer Entwicklung eines keinen Programms in VB.BET 2008 bin ich auf folgendes Problem gestoßen:

    Ich möchte eine Ordnerstruktur mit allen Dateien darin sehr schnell einlesen bzw. durchsuchen. Die Struktur umfasst ca. 20000 Dateien und 1000 Ordner. ich benötige das, weil User und auch Programme immer wieder Dateien in dieser Struktur verändern und ich nach bestimmten Inhalten Suchen möchte, die in eine Datenbank übergeben werden sollen.

    Nun habe ich verschiedene Ansätze ausprobiert und eine Lösung gefunden, die schon recht flott arbeitet. Gegenüber den gängigen Codebeispielen im Internet für C++/C# und VB.NET ist meine Suchklasse recht schnell. Ich arbeite mit Rekursion, Treading und Backroundworker und habe das ganze in vielen Testläufen optimiert. Dennoch gibt es immer wieder Beispiele dafür das es noch schneller geht.

    Wenn ich mir z.B. die Ordnereigenschaften in Vista anschaue, dauert das einlesen und ermitteln der Ordnergröße in dieser Struktur ca. 4 Sekunden. Mit meiner Routine ca. 18 Sekunden. Mit Superfinder ca. 58 Sekunden. Suchprogramme wie z.B Agent Ransack (ohne zu indizieren) aber auch z.B. Virenscanner durchsuchen eine solche Struktur in wenigen Sekunden.

    Wie funktioniert das so schnell? Kann das .NET Framework sowas überhaupt leisten? Ich vermute das diese Programme direkten Zugriff auf die Dateitabelle nehmen, in Assember geschrieben sind, vieleicht auch Kniffe verwenden (eben doch indizieren), o.ä. Eine API oder Codebeispiele habe ich dazu jedoch nicht gefunden.

    Hat jemand dazu eine Idee oder weiß wie das gemacht wird?

    Grüße an alle hier im Forum und vorab schon mal vielen Dank für Eure Antworten.

    Snaut ;o)

    • IP-Adresse ist Registriert
  • 16. Nov 2008 12:19 Antwort zu

    • gfoidl
    • Top 25 Mitwirkender
      Männlich
    • Registriert am 07. Okt 2008
    • Waidring / Tirol
    • Beiträge 177
    • Punkte 3.170

    Schnelles einlesen einer Ordnerstruktur mit allen Dateien

    Hallo,

    1. wenn du den Code schon so sehr optimiert hast wundert es mich dass du noch Rekursion verwendest. Eine Lösung mit einem Stack ist effizienter, da die Verwaltung für die Methoden-Aufrufe durch die Rekursion wegfallen. Außerdem besteht keine Gefahr eines StackOverflows.
      Schematisch:
      namespace gfoidl.Tools
      {
          public static class FileSystem
          {
              public static string[] GetAllFiles(string path)
              {
                  List<string> result = new List<string>();
                  Stack<string> stack = new Stack<string>();
      
                  stack.Push(path);
                  while (stack.Count > 0)
                  {
                      string curDir = stack.Pop();
                      foreach (string fileName in Directory.GetFiles(curDir))
                          result.Add(fileName);
      
                      foreach (string dirName in Directory.GetDirectories(curDir))
                          stack.Push(dirName);
                  }
      
                  return result.ToArray();
              }
          }
      }
    2. Du könntest auch den Index von Win verwenden. Ein Beispiel ist hier gezeigt.
    3. Eine weitere Möglichkeite wäre einmalig die Verzeichnisse zu durchsuchen und die Änderungen dann per FileSystemWatcher zu erhalten bzw. die einmalige Durchsuchung zu aktualisieren.

    mfG Günther
    Programming today is a race between the programmers and software engineers to create better
    and more idiot-proof programs, and the universe, creating bigger and better idiots. So far,
    the universe is winning". - Rich Cook
    • IP-Adresse ist Registriert
  • 16. Nov 2008 19:31 Antwort zu

    • snaut
    • Top 500 Mitwirkender
    • Registriert am 16. Nov 2008
    • Beiträge 4
    • Punkte 65

    Schnelles einlesen einer Ordnerstruktur mit allen Dateien

    Hallo Günther,

    danke für Deine Antwort.  Na ja, so arg optimiert habe ich nun auch wieder nicht.... ;o)

    Dein Tipp mit dem Stack ist super, auf die Idee bin ich einfach noch nicht gekommen. Ich werde es ausprobieren.

    Die Sache mit dem FileSystemWatcher hatte ich auch schon im Kopf. Bis jetzt habe ich den Gedanken aber noch nicht weiter verfolgt. Ich werde es auch damit mal versuchen. Wahrscheinlich läuft es auf eine Mischung aus den Varianten heraus.

    Mit dem Windows-Index ist so eine Sache. Eigentlich möchte ich nicht mit Windows-Indizes arbeiten. 

    Jedenfalls nochmal danke für die Tipps, manchmal fehlt nur der Anstoß in eine andere Richtung zu denken....

    Grüße, Snaut

     

    • IP-Adresse ist Registriert
  • 17. Nov 2008 8:23 Antwort zu

    • snaut
    • Top 500 Mitwirkender
    • Registriert am 16. Nov 2008
    • Beiträge 4
    • Punkte 65

    Schnelles einlesen einer Ordnerstruktur mit allen Dateien

    Hallo Günther,

    die Stack-Suche hat es gebracht. Statt in 18 Sek. läuft die Prozedur nun in 5 Sek. über die selbe Struktur. Super... 

    Nochmal vielen Dank.

    Gruß, Snaut ;o)

    • IP-Adresse ist Registriert
  • 17. Nov 2008 10:03 Antwort zu

    • gfoidl
    • Top 25 Mitwirkender
      Männlich
    • Registriert am 07. Okt 2008
    • Waidring / Tirol
    • Beiträge 177
    • Punkte 3.170

    Schnelles einlesen einer Ordnerstruktur mit allen Dateien

    Hallo,

    eine weitere Möglichkeite wäre
    string[] files = System.IO.Directory.GetFiles(path, "*", SearchOption.AllDirectories);

    Ist noch schneller, wirft aber Fehler wenn du keine Berechtigung hast. Sollte dies kein Problem sein dann nimm diese.

    mfG Gü
    Programming today is a race between the programmers and software engineers to create better
    and more idiot-proof programs, and the universe, creating bigger and better idiots. So far,
    the universe is winning". - Rich Cook
    • IP-Adresse ist Registriert
  • 17. Nov 2008 20:54 Antwort zu

    • snaut
    • Top 500 Mitwirkender
    • Registriert am 16. Nov 2008
    • Beiträge 4
    • Punkte 65

    Schnelles einlesen einer Ordnerstruktur mit allen Dateien

    Hallo Günther,

    hab ich schon probiert, läuft aber bei mir nicht. Aus dem Grund der auch in der Doku steht:

    Zitat:
    "Wenn Sie AllDirectories in der Suche auswählen und die Verzeichnisstruktur eine Verknüpfung enthält, sodass eine Schleife entsteht, befindet sich der Suchvorgang in einer Endlosschleife."

    Und das kann vorkommen, wenn auch ungewollt. Dann läuft der Thread endlos. Ist also nur bedingt zu gebrauchen.

    Gruß, Snaut ;o)

    • IP-Adresse ist Registriert
  • 14. Jul 2016 21:33 Antwort zu

    Schnelles einlesen einer Ordnerstruktur mit allen Dateien

    Hallo Gfoidl,

    Ich weiß das dein Beitrag schon etwas älter ist

    Aber dein Code ist wirklich schnell. Nur habe ich ein Problem, wenn ich das Laufwerk C durchsuchen möchte kommt es immer zu Zugriffsfehler.

    Zb: Ein Ausnahmefehler des Typs "System.UnauthorizedAccessException" ist in mscorlib.dll aufgetreten.

    Zusätzliche Informationen: Der Zugriff auf den Pfad "C:\Windows.old\WINDOWS\System32\config" wurde verweigert.

    Lassen sich diese Fehler mit deinem Code abfangen oder muss ich wirklich wieder auf die langsame Rekursive Methode umsteigen?

     

    Ich hoffe du kannst mir helfen.

    Grüße GR

    Normal 0 21 false false false DE X-NONE X-NONE /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Normale Tabelle"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-priority:99; mso-style-parent:""; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin-top:0cm; mso-para-margin-right:0cm; mso-para-margin-bottom:8.0pt; mso-para-margin-left:0cm; line-height:107%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri",sans-serif; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-fareast-language:EN-US;}
    • IP-Adresse ist Registriert
  • 15. Jul 2016 11:55 Antwort zu

    • gfoidl
    • Top 25 Mitwirkender
      Männlich
    • Registriert am 07. Okt 2008
    • Waidring / Tirol
    • Beiträge 177
    • Punkte 3.170

    Schnelles einlesen einer Ordnerstruktur mit allen Dateien

    Hallo,

    dazu lässt sich obiger Code ja anpassen, so dass er fehlertolerant wird.

    Z.B.:
    public static class FileSystem
    {
        public static IEnumerable<string> GetAllFiles(string root, bool ignoreUnauthorizedAccess = true)
        {
            Stack<string> stack = new Stack<string>();
    
            stack.Push(root);
            while (stack.Count > 0)
            {
                string curDir = stack.Pop();
                string[] files = null;
                try
                {
                    files = Directory.GetFiles(curDir);
                }
                catch (UnauthorizedAccessException) when (!ignoreUnauthorizedAccess)
                {
                    throw;
                }
    
                if (files != null)
                    foreach (string file in files)
                        yield return file;
    
                string[] dirs = null;
                try
                {
                    dirs = Directory.GetDirectories(curDir);
                }
                catch (UnauthorizedAccessException) when (!ignoreUnauthorizedAccess)
                {
                    throw;
                }
    
                if (dirs != null)
                    foreach (string dir in dirs)
                        stack.Push(dir);
            }
        }
    }

    Programming today is a race between the programmers and software engineers to create better
    and more idiot-proof programs, and the universe, creating bigger and better idiots. So far,
    the universe is winning". - Rich Cook
    • IP-Adresse ist Registriert
  • 15. Jul 2016 21:02 Antwort zu

    Schnelles einlesen einer Ordnerstruktur mit allen Dateien

    Vielen Dank für deine schnelle Antwort.

    Ich habe deinen Code jetzt für mich passend umgeschrieben (Visual Basic Programmierer im anfangsstadium) Smile

    Public Sub Suche_Dateien(ByVal pfad As String, ByVal endung As String)
            Dim stack As New Stack(Of String)()
            stack.Push(pfad)
            While stack.Count > 0
                Dim curDir As String = stack.Pop()
                Try
                Catch e As UnauthorizedAccessException
                    Continue While
                End Try
                Dim files As String() = Nothing
                Try
                    files = Directory.GetFiles(curDir, endung)
                Catch e As UnauthorizedAccessException
                    Continue While
                Catch e As System.IO.DirectoryNotFoundException
                    Continue While
                End Try
                For Each file As String In files
                    Try
                        Dim Dateigröße As FileInfo = New FileInfo(file)
                        DateienzuListview(listView1, (Path.GetFileNameWithoutExtension(file)), FormatByteSize(Dateigröße.Length))
                    Catch e As System.IO.FileNotFoundException
                        Continue For
                    End Try
                Next
                For Each dirName As String In Directory.GetDirectories(curDir)
                    stack.Push(dirName)
                Next
            End While
        End Sub

    Wie du vieleicht erkennen kannst suche ich nur nach einem bestimmten Dateityp. In diesem Fall MKV. Hast du möglicherweise eine Idee wie ich nach 2 oder 3 Dateitypen auf einmal suchen kann ohne die Funktin 2 oder 3 mal aufzurufen.

    Grüße Georg
    • IP-Adresse ist Registriert
  • 16. Jul 2016 0:37 Antwort zu

    • gfoidl
    • Top 25 Mitwirkender
      Männlich
    • Registriert am 07. Okt 2008
    • Waidring / Tirol
    • Beiträge 177
    • Punkte 3.170

    Schnelles einlesen einer Ordnerstruktur mit allen Dateien

    Hallo Georg,

    du brauchst nur die Dateierweiterungen irgendwie filtern. Z.B. so
            public static IEnumerable<string> GetAllFiles(string root, bool ignoreUnauthorizedAccess = true, params string[] extensions)
            {
                Stack<string> stack = new Stack<string>();
    
                stack.Push(root);
                while (stack.Count > 0)
                {
                    string curDir = stack.Pop();
                    string[] files = null;
                    try
                    {
                        files = Directory.GetFiles(curDir);
                    }
                    catch (UnauthorizedAccessException) when (!ignoreUnauthorizedAccess)
                    {
                        throw;
                    }
    
                    if (files != null)
                        foreach (string file in files)
                        {
                            string extension = Path.GetExtension(file);
    
                            if (extension.Length == 0)
                                yield return file;
                            else
                                if (extension != null && extensions.Contains(extension.Substring(1)))
                                    yield return file;
                        }
    
                    string[] dirs = null;
                    try
                    {
                        dirs = Directory.GetDirectories(curDir);
                    }
                    catch (UnauthorizedAccessException) when (!ignoreUnauthorizedAccess)
                    {
                        throw;
                    }
    
                    if (dirs != null)
                        foreach (string dir in dirs)
                            stack.Push(dir);
                }
            }


    Verwendung wäre dann z.B. so:
    FileSystem.GetAllFiles(root, true, "jpg", "png")


    In deinem Code gefällt mir das "DateienzuListview" nicht. Hier vermischt du Logik (Suchen der Dateien) mit der Anzeige. Das sind zwei verschiedene Anforderungen und sollten daher getrennt werden -> Seperation of Concerns.
    Gib als in dieser Methode nur das IEnumerable<string> für die gefundenen Dateien zurück und in der UI (User Interface, z.B. die Form) verwendest du diese Enumeration. So ist das sauber getrennt.

    mfG Gü

    Programming today is a race between the programmers and software engineers to create better
    and more idiot-proof programs, and the universe, creating bigger and better idiots. So far,
    the universe is winning". - Rich Cook
    • IP-Adresse ist Registriert
  • 16. Jul 2016 17:32 Antwort zu

    Schnelles einlesen einer Ordnerstruktur mit allen Dateien

    Ich danke dir vielmals!!!! Habe das ganze jetzt richtig in VB umgesetzt und es funktioniert einwandfrei.

    Nur eine Frage noch wenn ich direkt in ein Listview schreibe ist es doch eine Spur schneller als wenn ich zuerst in ein List of und von dort dan mit For each mein Listview fülle.

    Oder habe ich da einen Dekfehler?
    • IP-Adresse ist Registriert
  • 18. Jul 2016 12:29 Antwort zu

    • gfoidl
    • Top 25 Mitwirkender
      Männlich
    • Registriert am 07. Okt 2008
    • Waidring / Tirol
    • Beiträge 177
    • Punkte 3.170

    Schnelles einlesen einer Ordnerstruktur mit allen Dateien

    Hallo,

    es ist nur minimalst und nicht wahrnehmbar schneller, da es im Grunde nur eine Indirektion mehr ist. Das lässt sich auch kaum messen.

    Über "Seperation of Concerns" gibt es genügend Literatur (suche einfach mal danach), daher erspare ich mir hier ein Wiederholen der Vorteile dieser Trennung.
    Mir ist klar, dass es als Anfänger oft schwer ist das zu verstehen, aber v.a. mit der Zeit wird dir klar werden, dass alles andere eher ein Murks ist. Daher mein Rat es lieber gleich richtig machen.

    Noch dazu musst du in der UI (dem User Interface, also dort wo das ListView ist) auch keine weitere foreach-Schleife verwenden, sondern kannst dies per Datenbindung (Stichwort für die Suche: DataBinding) elegant erledigen (lassen). Anmerkung: mit WinForms hab ich schon länger nichts mehr richtig gemacht, daher weiß ich jetzt nicht ob das ListView die Datenbindung so super unterstützt.

    Auf https://github.com/gfoidl/Toolmaster30 hab ich dir ein Demo-Projekt gebastelt, indem auch diese Schichten getrennt sind. Der Vorteil ist einfach dass der Code nicht monolithisch und vermischt ist. Schaus dir einmal an und ziehe ein paar Anregungen daraus ;-)

    mfG Gü

    Programming today is a race between the programmers and software engineers to create better
    and more idiot-proof programs, and the universe, creating bigger and better idiots. So far,
    the universe is winning". - Rich Cook
    • IP-Adresse ist Registriert
Seite 1 von 1 (12 Treffer)

Regeln | Impressum