Lesegeschwindigkeit einer XML Datenbank erhöhen



  • Hallo,

    ich habe folgendes Problem: Ich schreibe gerade an einem Datei-Archivierungsprogramm, bei diesem wird ein entsprechendes Laufwerk nach allen vorhandenen Dateien durchsucht und diese in eine XML Datei geschrieben. Die Struktur sieht in etwa so aus:

    <?xml version="1.0" encoding="utf-8"?>
    <Database Volume="C:\" Itemsize="10000">
      <File Name="Datei1.test" Fullname="C:\Datei1.test" />
      <File Name="Datei2.test" Fullname="C:\Ordner1\Datei1.test" />
      .
      .
      .
    

    Wenn der Benutzer nun in einer Strukturansicht das Laufwerk auswählt, wird in einer Listenansicht diese Datenbank ausgelesen und die Dateien angezeigt. Jedoch gibt es ein massives Problem mit der Geschwindigkeit: Hab zum Test mal eines meiner Laufwerke durchsucht und ca. 200.000 Dateien gefunden... wenn diese jetzt aus der Datenbank gelesen werden sollen, dauert das quälend lange, etwa 1min oder länger. Der Algorithmus sieht (aufs wesentliche gekürzt) so aus:

    XmlTextReader r = new XmlTextReader(db);
    r.WhitespaceHandling = WhitespaceHandling.None;
    
    r.Read();
    r.Read();
    r.MoveToFirstAttribute();
    r.MoveToNextAttribute();
    
    int size = Convert.ToInt32(r.Value);
    
    List<ListViewItem> lvi = new List<ListViewItem>();
    ListViewItem tmp;
    
    while (r.Read())
    {
       if (r.NodeType == XmlNodeType.Element & r.Name.Equals("File"))
       {
          string name = r.GetAttribute("Name");
          string fullname = r.GetAttribute("Fullname");
    
          tmp = new ListViewItem();
          tmp.Text = name;
          tmp.SubItems.Add(fullname);
    
          lvi.Add(tmp);
       }
    }
    
    r.Close();
    
    ListViewItem[] lvis = new ListViewItem[lvi.Count];
    lvi.CopyTo(lvis);
    
    this.lv_mainlist.Items.AddRange(lvis);
    

    Gibt es vielleicht ne andere, bessere Variante oder Optimierung des Codes, so dass die Datenbank schneller ausgelesen werden kann? (bei Windows mit der Dateiindizierund der Suche gehts ja auch "schneller") oder brauche ich einen komplett anderen Ansatz? ... bei der Geschwindigkeit schweben mir so 5-10 sekunden vor 😃

    Danke schonmal vorweg! 👍



  • wenn du kein XML benutzt, sondern schlicht zeile für zeile schreibst, wie lange dauert's dann?



  • Prüf auch mal wielange AddRange() des ListViews da am rödeln ist - Bei vielen Einträgen macht evtl. der VirtualMode beim ListView mehr Spass 😉



  • danke schonmal... ich werde mal die variante ohne xml (sieht zwar nich so schön aus, aber wenns besser läuft 😉 ) ausprobieren, und eine frage hab ich zu dem virtual mode des listviewcontrols: wie macht man das? ich habs mal probiert mit der msn hilfe, aber es ist nichts brauchbares bei rausgekommen...



  • Zuerst nen EventHandler für .RetrieveVirtualItem schreiben!
    Dann .VirtualListSize auf die Anzahl der Einträge setzen.
    Dann .VirtualMode auf true setzen.

    private void ListView1_RetrieveVirtualItem(Object sender, RetrieveVirtualItemEventArgs e)
    {
        // Hier kriegst du via e.ItemIndex den Index des ListViewItems.
        // e.Item musst du hier dann selber setzen.
        // Die könntest du direkt aus deinem "List<ListViewItem> lvi" ziehen und kannst das AddRange sparen...
    }
    


  • also ich hab jetzt mal den Algo zum Lesen der Datenbank ohne XML geschrieben:

    StreamReader r = new StreamReader(db);
    
    string volume = (r.ReadLine().Split(new string[] { " " }, StringSplitOptions.None)[1].Split(new string[] { "=" }, StringSplitOptions.None)[1]);
    int size = Convert.ToInt32(r.ReadLine().Split(new string[] { "=" }, StringSplitOptions.None)[1]);
    
    // {...}
    
    List<ListViewItem> lvi = new List<ListViewItem>();
    ListViewItem tmp;
    
    foreach (string file in r.ReadToEnd().Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries))
    {
       string[] f_params = file.Split(new string[] { " " }, StringSplitOptions.None);
    
       tmp = new ListViewItem();
       tmp.Text = f_params[1].Split(new string[] { "=" }, StringSplitOptions.None)[1].Replace(":%20:", " ");
       tmp.SubItems.Add(f_params[2].Split(new string[] { "=" }, StringSplitOptions.None)[1].Replace(":%20:", " "));
    
       lvi.Add(tmp);
    
       // {...}
    }
    ListViewItem[] lvis = new ListViewItem[lvi.Count];
    lvi.CopyTo(lvis);
    
    this.lv_mainlist.Items.AddRange(lvis);
    

    Datenbank hat jetzt die Form:

    Database Volume=C:\
    Itemsize=1000
    File Name=Datei1.test Fullname=C:\Datei1.test
    File Name=Datei1.test Fullname="C:\Ordner1\Datei1.test
    File Name=Datei:%20:1.test Fullname="C:\Ordner1\Datei:%20:1.test
    .
    .
    .
    

    Das Auslesen dauert trotzdem noch sehr lange (bstimmt 40 sekunden bei 200000 Dateien)! Am der Listview AddRange Methode liegts nich, das geht rasend schnell...



  • Dauercoder schrieb:

    also ich hab jetzt mal den Algo zum Lesen der Datenbank ohne XML geschrieben:
    ...
    File Name=Datei1.test Fullname=C:\Datei1.test
    File Name=Datei1.test Fullname="C:\Ordner1\Datei1.test

    scherzkeks.
    ich meinte

    Datei1.test
    C:\Datei1.test
    Datei1.test
    C:\Ordner1\Datei1.test

    mit //kann kein c#

    while(not r.EndOfStream) {
       string a=f.ReadLine();
       string b=f.readLine();
       tmp = new ListViewItem(); 
       tmp.SubItems.Add(a,b); 
       lvi.Add(tmp); 
    }
    


  • Wenn du die Daten nicht redundant ablegst, dürfte es noch mal schneller sein.
    Den Dateinamen bekommst du ja recht einfach aus dem Pfad.



  • ...



  • ...



  • hab den Leistungskiller gefunden! Hab in der foreach-Schleife zusätzlich zu jeder Datei einen Statusbalken aktualisiert. Hab den jetzt raus genommen, und jetzt geht das rasend schnell 😉


Anmelden zum Antworten