Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Große strukturierte Textdateien laden - immer langsamer (https://www.delphipraxis.net/171109-grosse-strukturierte-textdateien-laden-immer-langsamer.html)

friedemann2009 20. Okt 2012 20:45

Große strukturierte Textdateien laden - immer langsamer
 
Schönen Abend zusammen,

ich habe ein Problem mit dem Laden von großen Textdateien. Hintergrund: Ich nutze in einem Prog ein eigenes Datenformat aus verschachtelten Arrays, Dictionaries (Hash) und Records. Die Arrays werden durch verschiedene Prozesse mit zahlreichen Daten gefüllt. Um manche aufwendige BErechnungen der Daten nicht mehrfach machen zu müssen, habe ich mir eine eigene Routine geschrieben, mit der die Daten der Reihe nach in eine Textdatei geschrieben und die Datei am Ende mit ZLib komprimiert wird. Das funktioniert auch mit sehr großen Datenmengen sehr gut und schnell (wenige Sekunden). Aso, die Einzeldaten werden mit <Tags> in die Datei geschrieben.

Wenn ich die Datei jetzt wieder laden möchte, dauert das exponentiell (!) länger: also nicht nur fast eine Stunde (!), sondern auch von Einzeldatum zu Einzeldatum länger! Praktisch "lade" ich so:
- Datei dekomprimieren
- Datei in Stringlist laden
- via Schleifen und Pos() die Tags einzeln suchen, größere Einheiten kopieren, Einzeldaten darin auswerten und je nach Datentyp in die jeweiligen Container (Array usw.) verschieben.

Ich vermute stark, dass es an POS und Copy-Anweisungen liegt, aber habe keine Ahnung, wie ich das optimieren / ersetzen könnte. - Habe aber auch sehr wenig Erfahrung im Umgang mit Datenspeicherung/-laden.

Hat jemand einen Rat?

Danke und schöne Grüße,
Frieder (XE3)

jfheins 20. Okt 2012 21:00

AW: Große strukturierte Textdateien laden - immer langsamer
 
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;
};

friedemann2009 20. Okt 2012 21:25

AW: Große strukturierte Textdateien laden - immer langsamer
 
Abend jfheinz,

danke für Deine Antwort. Ich Grunde habe ich mir ja - so denke ich mir - einen Parser geschrieben. Was mich wundert ist: Jeder Parser muss doch mit Suchen und Kopieren arbeiten; was macht dann mein Auslesen so viel langsamer?

Ich hatte das Problem schon öfters; sobald eine stringlist etwas größer wird und man sie sukzessive durcharbeiten muss (via POS/Copy), wird es bald sehr langsam.. Gibt es eine andere Alternative?

Schöne Grüße,
Frieder

jaenicke 20. Okt 2012 21:38

AW: Große strukturierte Textdateien laden - immer langsamer
 
Zitat:

Zitat von friedemann2009 (Beitrag 1187760)
Jeder Parser muss doch mit Suchen und Kopieren arbeiten; was macht dann mein Auslesen so viel langsamer?

Ein Parser kann sehr gut mit Pointern arbeiten. Einen recht schnellen habe ich in meinem Registryeditor geschrieben:
http://www.delphipraxis.net/137675-r...rsion-7-a.html
Der schafft das Lesen und Parsen eines Registry-Exportes mit ca. zwei Dritteln der sequentiellen Festplattengeschwindigkeit.

Ein anderer Parser, den ich beruflich für eine eigene Skriptsprache geschrieben habe, arbeitet auch komplett pointerbasiert und ist dadurch sehr schnell. Denn der Quelltext an sich bleibt wo er ist, zur Analyse wird nur ein PChar-Pointer verschoben und das auch nur in eine Richtung, sprich Single-Pass.

friedemann2009 20. Okt 2012 21:47

AW: Große strukturierte Textdateien laden - immer langsamer
 
Ah, ok, jetzt verstehe ich das mal. Tja, in meinem Fall hätte ich keine Ahnung, wie ich da mit Pointern arbeiten soll -, dafür fehlt mir die Erfahrung.. Ich kannte Pointer bislang nur insofern, als damit ein Zeiger auf ein komplettes Datum (also z.B. eine Integer, ein String o.ä.) verschoben werden kann. Wie aber soll man *innerhalb* eines Datums (wie eine Textdatei) einen Zeiger verschieben? Habt Ihr da zufällig einen Link fürs erste Reinschauen zur Hand?

Danke und schöne Grüße,
frieder

friedemann2009 20. Okt 2012 22:28

AW: Große strukturierte Textdateien laden - immer langsamer
 
Sorry, dass ich nochmal nachfrage: Ich lese gerade nochmal über Datenspeicherung via Streams. Könnte das Laden via Streams schneller gehen anstelle via Textdateien?

Danke und schönen Abend,
frieder

jaenicke 20. Okt 2012 22:47

AW: Große strukturierte Textdateien laden - immer langsamer
 
Die schnellste Variante sind MMFs wie ich sie in meinem Programm auch nutze. ;-)
Schau es dir einfach mal an, das ist nicht so kompliziert.

jfheins 21. Okt 2012 02:31

AW: Große strukturierte Textdateien laden - immer langsamer
 
Hallo,
Zitat:

Zitat von friedemann2009 (Beitrag 1187760)
danke für Deine Antwort. Ich Grunde habe ich mir ja - so denke ich mir - einen Parser geschrieben. Was mich wundert ist: Jeder Parser muss doch mit Suchen und Kopieren arbeiten; was macht dann mein Auslesen so viel langsamer?
Ich hatte das Problem schon öfters; sobald eine stringlist etwas größer wird und man sie sukzessive durcharbeiten muss (via POS/Copy), wird es bald sehr langsam.. Gibt es eine andere Alternative?

Um eine einigermaßen gute Laufzeit zu bekommen, darfst du die eigentliche Datei nur einmal durchgehen. Also während des Durchgangs nicht Pos(Datei, ...) aufrufen, weil da steckt wieder eine Schleife srin. Und dann hast du vermutlich ein quadratisches Laufzeitverhalten. Du kannst z.B. immer ein Zeichen lesen (am besten hier schon irrelevante Zeichen überspringen) und in einen Puffer schreiben. Dann gucken ob in dem Puffer ein gültiges Token ist. Falls ja, Puffer leeren und Token verarbeiten (hierbei werden ggf. wieder Zeichen gelesen) und weitermachen.
Der "Trick" ist, dass der Puffer immer nur klein ist. In meinem Fall habe ich das über die Zeilen realisiert: Da die Datei Zeilenweise verarbeitet wird, habe ich immer nur einen Text von vll. 30 Zeichen, der einem Token zugeordnet werden muss.

nuclearping 21. Okt 2012 08:57

AW: Große strukturierte Textdateien laden - immer langsamer
 
Zitat:

Zitat von friedemann2009 (Beitrag 1187767)
Ah, ok, jetzt verstehe ich das mal. Tja, in meinem Fall hätte ich keine Ahnung, wie ich da mit Pointern arbeiten soll -, dafür fehlt mir die Erfahrung.. Ich kannte Pointer bislang nur insofern, als damit ein Zeiger auf ein komplettes Datum (also z.B. eine Integer, ein String o.ä.) verschoben werden kann. Wie aber soll man *innerhalb* eines Datums (wie eine Textdatei) einen Zeiger verschieben? Habt Ihr da zufällig einen Link fürs erste Reinschauen zur Hand?

Danke und schöne Grüße,
frieder

Ist nicht so schwer, wie man sich das vielleicht denken mag.

Beispiel:
Delphi-Quellcode:
var
  MyString: String;
  MyPtr: Pointer;
begin
  MyString := 'Hallo Welt';
  GetMem(MyPtr, Length(MyString));
  try
    Move(MyString[1], MyPtr^, Length(MyString)); // "Hallo Welt" steht nun im Pointer
   
    Finalize(MyString);
    SetLength(MyString, 5);
    Move(MyPtr^, MyString[1], 5); // "Hallo" wird aus dem Pointer kopiert
  finally
    FreeMem(MyPtr);
  end;
end;
Oder:
Delphi-Quellcode:
var
  MyString: String;
  MyPtr: PChar;
  i, j: Integer;
  Found: Boolean;
begin
  MyString := '12345|Test';
  GetMem(MyPtr, Length(MyString));
  i := Integer(MyPtr); // Addresse vom Pointer merken
  try
    Move(MyString[1], MyPtr^, Length(MyString));
    Found := FALSE;
    j := 1;
    repeat
      if MyPtr^ = '|' then
        Found := TRUE; // Trennzeichen gefunden, irgendwas machen
      Inc(MyPtr^);
      Inc(j);
    until Found or (j > Length(MyString));
  finally
    MyPtr := PByte(i); // Addresse vom Pointer wiederherstellen
    FreeMem(MyPtr);
  end;
end;

Furtbichler 21. Okt 2012 10:21

AW: Große strukturierte Textdateien laden - immer langsamer
 
Na ja, Leute. Wenn mit 'Pointer' wirklich ein PChar gemeint ist, dann ist das 'Optimieren auf hohem Niveau'. Damit kann man sein Programm um einen Faktor X (so 10% schätze ich, von mir auch auch 20%) schneller machen. Auch der wirklich sinnvolle Hinweis, mit MMF einzulesen, bringt bei sehr großen Dateien eine drastische (aber konstante) Verbesserung (wieder um einen Faktor).

Hier geht es aber zunächst um das Verfahren. alsp das 'wie'. Die Vorredner haben hier Recht: Einen Parser kann man mit einer Komplexität von O(n) hinbekommen, d.h. er verhält sich von der Laufzeit so, das er bei einer Verdoppelung der Inputlänge auch nur doppelt so lange für die Verarbeitung braucht.

Dein Algorithmus scheint bei mindestens O(n^2) zu liegen (d.h. er vervierfacht die Zeit bei Verdopplung der Input-größe), aber wie sollen wir wissen, wie wir dir helfen können, wenn wir noch keine Zeile Code gesehen haben?


Zitat:

Zitat von friedemann2009 (Beitrag 1187753)
Praktisch "lade" ich so:
- Datei dekomprimieren
- Datei in Stringlist laden
- via Schleifen und Pos() die Tags einzeln suchen, größere Einheiten kopieren, Einzeldaten darin auswerten und je nach Datentyp in die jeweiligen Container (Array usw.) verschieben.

Der letzte Punkt dürfte der Entscheidende sein.

Bummi 21. Okt 2012 10:53

AW: Große strukturierte Textdateien laden - immer langsamer
 
Wie wäre es mit einer Verwaltungsstruktur am Anfang/Ende der Datei, oder in einer eigenen Datei, welche die Offsets,Länge und den Typ der Objekte beinhaltete. Die Objekte selbst werden dann gezielt per passendem Streamreader/writer geschrieben und gelesen?

jaenicke 21. Okt 2012 11:06

AW: Große strukturierte Textdateien laden - immer langsamer
 
Zitat:

Zitat von nuclearping (Beitrag 1187780)
Ist nicht so schwer, wie man sich das vielleicht denken mag.

Auweia, das ist aber auch bei weitem nicht so schwer wie du es jetzt gepostet hast. :shock:

Beispiel:
Delphi-Quellcode:
var
  MyString: String;
  MyPtr: PChar;
begin
  MyString := 'Hallo Welt';
  MyPtr := PChar(MyString);
  ShowMessage(Copy(MyPtr, 1, 5)); // 'Hallo'
  Inc(MyPtr, 6);
  ShowMessage(MyPtr); // 'Welt'
end;
Mit Inc und Zeichenzugriff via MyPtr^ lässt sich das bequem machen. Untypisiert mit dem Typ Pointer macht doch gar keinen Sinn...

himitsu 21. Okt 2012 11:11

AW: Große strukturierte Textdateien laden - immer langsamer
 
Zitat:

Copy(MyPtr, 1, 5)
Copy arbeitet mit Strings, also wird der kompette PChar, bis zur nächsten #0 in einen String kopiert, dann davon via Copy ein Teil rauskpiert und zum Schluß der String wieder freigegeben.

Nimm da lieber SetString.


Zitat:

Zitat von nuclearping (Beitrag 1187780)
Beispiel:
Delphi-Quellcode:
var
  MyString: String;
  MyPtr: Pointer;
begin
  MyString := 'Hallo Welt';
  GetMem(MyPtr, Length(MyString));
  try
    Move(MyString[1], MyPtr^, Length(MyString)); // "Hallo Welt" steht nun im Pointer
   
    Finalize(MyString);
    SetLength(MyString, 5);
    Move(MyPtr^, MyString[1], 5); // "Hallo" wird aus dem Pointer kopiert
  finally
    FreeMem(MyPtr);
  end;
end;
...

Und jetzt haben wie wieder vergessen, daß es Unicode gibt und schon is der String futsch




Menno, ich finde es nicht mehr, aber ich dachte ich hätte mal eine Funktion gesehn (direkt im Delphi), welche einen String nimmt und einem daraus einen PChar erzeugt. Also das GetMem und Move direkt verbaut, wo man dann nicht an Unicode denken muß.

DeddyH 21. Okt 2012 11:36

AW: Große strukturierte Textdateien laden - immer langsamer
 
Meinst Du Delphi-Referenz durchsuchenStrPCopy?

nuclearping 21. Okt 2012 13:44

AW: Große strukturierte Textdateien laden - immer langsamer
 
Zitat:

Zitat von himitsu (Beitrag 1187791)
Und jetzt haben wie wieder vergessen, daß es Unicode gibt und schon is der String futsch

Mein Gott dann mach halt aus der 5 'n Length('Hallo') ... Sicher sind die Beispiele nicht perfekt, aber man kann auch pingelich sein, solche Erbsenzählerei, meine Güte ... :wall:

Furtbichler 21. Okt 2012 13:50

AW: Große strukturierte Textdateien laden - immer langsamer
 
Hmm.... Ok, der Unterschied zwischen O(n) und O(n^2) ist wohl doch Pchar statt String...

Hmmpfrl.

himitsu 21. Okt 2012 13:51

AW: Große strukturierte Textdateien laden - immer langsamer
 
Schutz des Programms?

Früher konnte man höchstens Controls aus der DFM entfernen, wenn man die Resourcen der EXE bearbeitet, aber dank CodeBinding kann man glatt die komplette GUI umbauen/erweitern, nur indem man die DFM bearbeitet.


Zitat:

Mein Gott dann mach halt aus der 5 'n Length('Hallo') ...
Es ging nicht um die 5 und Length hilft da auch nix.

Delphi-Quellcode:
SizeOf(Char)
:zwinker:

nuclearping 21. Okt 2012 13:58

AW: Große strukturierte Textdateien laden - immer langsamer
 
Zitat:

Zitat von jaenicke (Beitrag 1187790)
Auweia, das ist aber auch bei weitem nicht so schwer wie du es jetzt gepostet hast. :shock:

Es ging hauptsächlich darum, dem TE EINEN Weg zu zeigen, wie er mit Pointern und Strings arbeiten kann, ohne Copy, Pos, etc. zu verwenden.

himitsu 21. Okt 2012 14:58

AW: Große strukturierte Textdateien laden - immer langsamer
 
Hab's gefunden (in falscher Unit gesucht :oops:)

Delphi-Referenz durchsuchenStrNew, welches man allerdings nur mit StrDispose wieder freigeben kann (es sei denn man rechnet die kranke Längenangabe raus)


Zitat:

Zitat von DeddyH (Beitrag 1187792)
Meinst Du Delphi-Referenz durchsuchenStrPCopy?

Hmmm, nicht ganz ... das kopiert ja nur, aber reserviert keinen Speicher.
Ich mein eher sowas sie DupStr/StrDup aus C++.

Nja, aber StrLCopy (weil ja nicht der ganze String kopiert werden soll), zusammen mit einem GetMem würde sich gut in einer Funktion machen.

Delphi-Quellcode:
function DupStr(str: PAnsiChar; MaxLen: NativeInt = -1): PAnsiChar; override; // MaxLen incl. #0
function DupStr(str: PWideChar; MaxLen: NativeInt = -1): PWideChar; override;

function DupStr(str: PAnsiChar; MaxLen: NativeInt = -1): PAnsiChar;
begin
  if MaxLen = 0 then
    Exit(nil);
  if MaxLen < 0 then
    MaxLen = StrLen(str) + 1;
  Result := GetMemory(MaxLen * SizeOf(str^));
  try
    StrLCopy(Result, str, MaxLen);  
  finally
    FreeMemory(P);
  end;
end;

function DupStr(str: PWideChar; MaxLen: NativeInt = -1): PWideChar;
...
Delphi-Referenz durchsuchenNewStr und Delphi-Referenz durchsuchenDispose für PChars (man darf nur nicht vergessen, daß Delphi dort noch eine Längenangabe drin versteckt)
Delphi-Referenz durchsuchenSetString = von PChar zu String
DupStr = von PChar/String zu PChar

friedemann2009 21. Okt 2012 17:36

AW: Große strukturierte Textdateien laden - immer langsamer
 
Abend zusammen,

wow, :shock: - da hab ich ja ne Diskussion losgetreten.. Vielen Dank für die vielen Anregungen! Ich versuche mal die Möglichkeiten für eine Optimierung zu sortieren:

- Ohne Pointer: soviel POS wie möglich raus, Stringlist möglichst nur einmal durchlaufen, ggf. kleinere Puffer bilden.

-> Das war bisher in etwa auch mein Ansatz. Das Problem ist dabei aber die Datencodierung a la 'Quasi'-XML, also mit Anfangs- und Endtag, fortlaufend, Baumstruktur. Bisher habe ich noch nicht mit fertigen XML-Parsern gearbeitet.

- Mit Pointern: Vielen Dank für die Code-Bsp. Ich muss aber leider gestehen, dass ich sie nicht wirklich verstehe. Mir ist wohl immer noch nicht die Logik klar, mit der man "Pointer verschieben" kann u.ä. Ohne Pointer, zB bei Strings ist mir klar: Ich kann mit einem Index und einem Count Teile eines Strings kopieren, löschen etc, quasi Intervalle herausschneiden und in einen neuen Topf gegeben und weiterverarbeiten. Wie soll das bei Pointern gehen? Wie kann ich da 'Intervalle' von Daten definieren, wenn ich doch nur mit EINEM Zeiger auf EINEN 'Punkt' (also z.B. eine ganze Variable im Speicher) verweise? Bräuchte ich - für Intervalle wie '234' in '12345' nicht zwei Pointer? Da steh ich aufm Schlauch..

- Streams: Das scheint mir die naheliegendste, weil auch gerade am einfachsten umzusetzende Lösung zu sein. Die Reihenfolge der Datenspeicherung/-ladung ist klar. Ob das dann wirklich schneller wird, weiß ich noch nicht. Muss ich ausprobieren. Es dürften damit aber einige POSes entfallen.

Falls noch jemand einen Tipp zum Pointer-Verständnis hat (gerne auch am Bsp. von jaenicke), würde ich mich freuen.

Ansonsten nochmal herzliches Dankeschön und einen schönen Sonntagabend wünscht Euch
frieder

jaenicke 21. Okt 2012 20:39

AW: Große strukturierte Textdateien laden - immer langsamer
 
Ja, du siehst das richtig was Pointer angeht. Ich habe z.B. immer einen Startpointer für den aktuellen Bereich und einen Laufpointer. Habe ich dann ein Element identifiziert, kopiere ich einfach ab dem Startpointer den String heraus. Die Länge bekomme ich durch die Differenz mit dem Laufpointer.

Auf diese Weise muss nur etwas kopiert werden, wenn ich auch etwas herauskopieren will.

Ein Beispiel kann ich erst morgen Abend liefern, wenn nötig.

friedemann2009 21. Okt 2012 21:22

AW: Große strukturierte Textdateien laden - immer langsamer
 
Ok, danke!

Ich habe mich jetzt dran gemacht und das ganze zunächst als FileStream / StringToStream zu lösen. Leider habe ich jetzt das Problem, dass offenbar die Strings falsch geschrieben und/oder gelesen werden: Wenn ich "True" schreibe, kommt zumindest (spätestens) beim Lesen ein "TrXX" (XX = komische Zeichen). Ich vermute, es ist ein Codierungsproblem (PChar usw.). Habe dahingehend schon im Forum gesucht, aber die Lösungsvorschläge dort (für D2009) haben nicht funktioniert.

Mein Code für das Speichern/Lesen der Strings und Integer:


Delphi-Quellcode:
Function StreamToString(aStream: TStream): string;
var
  Len: longint;
  tempstr: String;
begin
  aStream.Read(Len, SizeOf(Len));
  SetLength(tempStr, Len);
  aStream.Read(PChar(tempStr)^, Len);
  result:= tempStr;
end;

Function StreamToInteger(aStream: TStream): integer;
var
  tempint: integer;
begin
  aStream.Read(tempint, SizeOf(tempint));
  result:= tempint;
end;

//----------

Procedure StringtoStream(aStream: TStream; astring: string);
var
  len: longint;
begin
  len:= Length(astring);
  aStream.Write(len, Sizeof(Len));
  aStream.Write(PChar(aString)^, Len);
end;

Procedure IntegertoStream(aStream: TStream; aint: integer);
begin
  aStream.Write(aint, SizeOf(aint));
end;
Ich nutze Delphi XE3 - und die Strings sind von 0 Zeichen bis sehr große Datentabellen-Strings (und sollten eigentlich überall AnsiString sein).

Wenn ich anstelle von PChar einfach AnsiChar nehme, bekomme ich einen Error für ungültige Typumwandlung.

Danke und schöne Grüße,
frieder

himitsu 21. Okt 2012 22:11

AW: Große strukturierte Textdateien laden - immer langsamer
 
Dennoch nimm PAnsiChar und AnsiString.

String/PChar hat seit Delphi 2009 zwei Byte pro Zeichen und in deinen Dateien ist es aber nur mit 1 Byte pro Zeichen gespeichert.


Und was ist die "entgültige" Typumandlung?


PS: Bezüglich der Unicodeumsellung gibt es zahlreiche Threads und Tutorials.

Grundsätzlich kann man sagen, daß es deine eigene Schuld war, daß jetzt nichts mehr läuft, denn man sollte niemals dynamische Typen binär speichern/übertragen, sonsdern ausschließlich generische Typen, welche unveränderlich sind.
Das fing bei Unicode an, wo tring, Char und PChar sich veränderten und geht nun mit 64 Bit weiter.

nuclearping 22. Okt 2012 06:49

AW: Große strukturierte Textdateien laden - immer langsamer
 
@friedemann: Mal was gänzlich anderes. Warum benutzt du eigentlich nicht gleich eine ordentliche Datenbank, wie zB Firebird, um deine Sachen abzulegen? :mrgreen:

friedemann2009 22. Okt 2012 09:31

AW: Große strukturierte Textdateien laden - immer langsamer
 
Zitat:

Zitat von nuclearping (Beitrag 1187855)
@friedemann: Mal was gänzlich anderes. Warum benutzt du eigentlich nicht gleich eine ordentliche Datenbank, wie zB Firebird, um deine Sachen abzulegen? :mrgreen:

Ja, das wäre dann der nächste Schritt. Offen gesagt: Ich bin von Haus aus kein Programmierer, sondern Linguist, der sich seit 5 Jahren Lerning-by-doing durch Delphi schlägt und methodische Verfahren zur Sprach- und Imageanalyse entwickelt.. - Welche Code-Richtung meine Progs jeweils eingeschlagen haben, hing von meinen bisherigen Projekten, zufälligen Google-Treffern und Tipps hier aus dem Forum ab.. Eine DB war unter den Tipps bisland nicht ;)

Zitat:

Zitat von himitsu (Beitrag 1187845)
Grundsätzlich kann man sagen, daß es deine eigene Schuld war, daß jetzt nichts mehr läuft, denn man sollte niemals dynamische Typen binär speichern/übertragen, sonsdern ausschließlich generische Typen, welche unveränderlich sind.

Ja, das merke ich gerade auch. Da fehlt mir eben das Basis-Wissen zur Entwicklung der unterschiedlichen Datentypen, sorry..:oops:

Habe AnsiChar einsetzen können, jetzt läuft alles.

- Durch das Abspeichern/Laden der Daten via Streams geht der Prozess insgesamt deutlich schneller.

Danke Euch allen für die Anregungen und Tipps, schöne Woche,
frieder

himitsu 22. Okt 2012 10:14

AW: Große strukturierte Textdateien laden - immer langsamer
 
Zitat:

Zitat von friedemann2009 (Beitrag 1187869)
Ja, das merke ich gerade auch. Da fehlt mir eben das Basis-Wissen zur Entwicklung der unterschiedlichen Datentypen, sorry..:oops:

Mach dir nichts draus ... das haben die Meisten falsch gemacht, bzw. nicht gewusst/beachtet.

Wobei es auch anders kommen kann.
Bei 64 Bit war mal der Integer/Cardinal veränderlich und nun hat man den einfach eingefroren und einen neuen Typen erfunden.
Das gibt jetzt also beim Speichern/Laden/Übertragen weniger Problemem aber dafür dann im Programm, weil ganz Viele zwischen Pointer und Integer gecastet haben (was eigentlich auch gepaßt hätte), aber nun eben Datenverlust mit sich bringt, weil vom Pointer die Hälfte verloren geht.



PS: Ich versuche hier grade ein Projekt "eigentlich" auf 64 Bit zu portieren, aber was darin alles gemacht wurde ... da wird einem Schlecht.
z.B. wurden erstmal alle Warnungen deaktiviert. OK, die Meisten Warnungen sind nur String<>AnsiString-Warnungen, wo Delphi es aber automatisch npasst, aber dazwischen waren auch welche, wo Delphi nichts anpassen konnte. PChar<>PAnsiChar und dann wundert man sich, daß Einiges nicht geht :wall:
Also immer schön auf den Compiler hören.


Nja, einfacher hättest du es mit TReader/TWriter gehabt.
Das beachtet selbst das Format und speichert es sogar in der Datei mit ab, so daß man die Datei auch noch auslesen könnte, selbst wenn etwas nicht paßt.
Das kennst du z.B. von der DFM und wenn es gewisse Komponenten oder Property nicht mehr gibt.

p80286 22. Okt 2012 11:49

AW: Große strukturierte Textdateien laden - immer langsamer
 
@Himitsu
nun laß mal gut sein. Auch wenn Du Recht hast, das "Typ-Problem" ist doch hausgemacht.
Nimm doch einfach den "integer". Das ist eine ganze Zahl mit Vorzeichen, und je nach Compiler/Rechner 8/16/32/64 Bit breit das kann man doch nicht ernst nehmen. Mit Rücksicht auf die lernschwächeren unter uns ist alles Integer und Char ?
Solange in den Hanbüchern noch diese Verdummung betrieben wird wirst Du auch immer die gleichen Probleme haben.
(was ist gegen word16,word32,word64 einzuwenden?)

Gruß
K-H

Sherlock 22. Okt 2012 12:16

AW: Große strukturierte Textdateien laden - immer langsamer
 
Es scheinen ja hier mehrere Probleme eine schöne Summe von Performance zu kosten. Ein Teilproblem ist sicherlich die Verwendung von Stringlisten. Wir hatten auch Dateien auszulesen, und haben dabei numerische "Tags" als Strings eingelesen und als Sortierschlüssel für die Stringlisten verwendet. Stringvergleiche sind aber langsam...so richtig langsam. Deshalb sind wir auf Arrays umgestiegen in denen besagte "Tags" wirklich numerisch vorliegen, das flitzt jetzt erheblich schneller. Wenn also Deine Listen sortiert sind/sein müssen, dann empfehle ich von Strings als Sortierkriterien wegzugehen, oder einen effizenteren Vergleichsalgorithmus zu finden.

Sherlock

p80286 22. Okt 2012 12:49

AW: Große strukturierte Textdateien laden - immer langsamer
 
Solange wir nicht wissen, wie der Source wirklich aussieht, sind das alles nur gutgemeinte Ratschläge.
Und der Unterschied zwischen gut gemeint und gut gemacht ist bekanntlich gewaltig.

Gruß
K-H


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:00 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz