Einzelnen Beitrag anzeigen

Benutzerbild von jfheins
jfheins

Registriert seit: 10. Jun 2004
Ort: Garching (TUM)
4.579 Beiträge
 
#2

AW: Große strukturierte Textdateien laden - immer langsamer

  Alt 20. Okt 2012, 21:00
Hi,
also damit das wirklich exponenziell geht, da müsstest du schon was ganz falsch gemacht haben - aber kubische Laufzeit ist auch schon nicht toll.
zu deinem Problem: Du solltest dir entweder selbst einen Parser schreiben (einmal durchgehen muss reichen!) oder du wechselst das Dateiformat und nimmst einen vorhandenen Parser.
Zum Beispiel gibt es viele flotte XML Parser, und du kannst das Format relativ flexibal anpassen.
Und so als "goodie" kannst du auch eine XSD schreiben und prüfen ob eine Datei die von dir erwartete Struktur besitzt.

Falls du einen einfachen Parser schrieben willst: Da gibt es ganz viele Konzepte und es kann sehr komplex werden. Ich habe auch mal einen geschrieben, leider in java. Habe ihn dir trotzdem mal angehängt. Grob lässt sich das in einen Tokenizer einteilen, der kleine Stücke aus dem Text extrahiert ("Kleinstes Element, das eine Bedeutung hat") und dann einen teil, der die Tokens verarbeitet.
In dem Beispiel werden Objekte aus einer Datei gelesen. Jedes Objekt hat dabei seine eigene "aus der Datei laden" Funktion.
Der Parser lädt die Datei Zeilenweise und lässt dann einen RegEx auf die Zeile los. Das ist jetzt eine relativ "einfache" Methode, weil der RegEx da einige Arbeit abnimmt die man sonnst selber machen müsste.
Heraus kommt ein "Baum" an Objekten in der Variable root.
Code:
package MainPack;

import HelperClasses.TElement;
import ItemClasses.*;
import java.util.*;
import java.util.regex.*;
import javax.swing.JOptionPane;

public class TParser
{
    ArrayList<TItem> FItemArray;
    TElement root;
   
    /** Creates a new instance of TParser
     * TParser is used to parse a text file into the abstract hirachial data structure,
     * implemented by TElement. For simplicity, one root element is created which is not
     * actually in the file. all elements in the file are then added to this root element
     * as a child. After this, we can easily unserialise the while tree by talking each of
     * the root childs and calling its "toMainObject()" Method. This will return a TItem object
     * which in turn can easily be added o the ArrayList that is returned afterwards.
     */
    public TParser(ArrayList<TItem> AItemArray)
    {
   FItemArray = AItemArray;
   root = new TElement("root");
    }
   
    public void Parse(Scanner File)
    {
   File.useDelimiter(Pattern.compile("[\n]"));
   
   Pattern pnewobj =   Pattern.compile("^(new T)(.+)\\{");
   Pattern pnewchild = Pattern.compile("^(.+)=new T(.+)\\{");
   Pattern pstrprop =  Pattern.compile("^(.+)=\"(.*)\";");
   Pattern pproperty = Pattern.compile("^(.+)=(.+);");
   
   Matcher mnewobj;
   Matcher mnewchild;
   Matcher mstrprop;
   Matcher mproperty;
   
   String token = "";
   TElement current = null;
   
   while (File.hasNext()) // Nächste Zeile laden
   {
       token = File.next().trim();
       if (!token.equals(""))
       {      
      mnewobj =  pnewobj.matcher(token);
      mnewchild = pnewchild.matcher(token);
      mstrprop = pstrprop.matcher(token);
      mproperty = pproperty.matcher(token);
      
      // We now get the tokens one after another, without empty tokens ...
      
      if (mnewobj.matches()) // new Item-Object to read
      {
          current = root.addRootChild(mnewobj.group(2));
          //        ^^^^ current also possible, root more error resistant
      }
      else if (mnewchild.matches()) // Child-Object
      {
          current = current.addChild(mnewchild.group(1), mnewchild.group(2));
      }
      else if (mstrprop.matches()) // String-Property to read
      {
          String str = mstrprop.group(2);
         
          str = str.replace("(\\\\)*\\n", "\n"); // replace non-escaped \n's with line break
          str = str.replace("\\\\", "\\"); // replace escaped backslashes with backslash
         
          current.addProperty(mstrprop.group(1), str);
      }
      else if (mproperty.matches()) // Other Property to read
      {
          current.addProperty(mproperty.group(1), mproperty.group(2));
      }
      else // Control-Chars
      {
          if (token.matches("\\};?")) // Klammer zu => Ebene hoch
         current = current.getParent();
          else
         System.err.println("Unrecognised token: \"" + token + "\"");
      }
       }
   }
   
   int child = 0;
   int errors = 0;
   String messages = "";
   
   for (Object elem : root.getRootChilds())
   {
       try
       {
      FItemArray.add(((TElement)elem).readMainObject());
       }
       catch (IllegalArgumentException e)
       {
      errors++;
      messages = messages + "\n" + "root[" + child + "](" + ((TElement)elem).getObjectName() + ")." + e.getMessage();
       }
       child++;
   }
   if (errors > 0)
       JOptionPane.showMessageDialog(null, errors + " Object(s) could not be imported, as properties were invalid:" + messages, "Errors during Import", JOptionPane.ERROR_MESSAGE);
    }
}
Geparst wird ein Text, der ungefähr so aussehen sollte:
Code:
new TYearly{
   Title="My Birthday";
   Priority=30;
   DaysInAdvance=1;
   Description="My Birthday ...";
   StartDate=new TDate{
      Year=2007;
      Month=3;
      Day=16;
      Time=null;
   };

   EndDate=new TDate{
      Year=2026;
      Month=3;
      Day=16;
      Time=null;
   };

   Day=12;
   Month=3;
};

Geändert von jfheins (20. Okt 2012 um 21:05 Uhr)
  Mit Zitat antworten Zitat