Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Problem mit großer Textdatei (https://www.delphipraxis.net/165628-problem-mit-grosser-textdatei.html)

PeSch 9. Jan 2012 15:58

Problem mit großer Textdatei
 
Hallo Leute,

Bin neu im Forum und weiss nicht ob ich hier in der richtigen Kategorie bin.

Vorab: Suchfunktion habe ich schon benutzt, was ich gefunden habe reicht mir nicht :lol:.

Folgendes Problem: ich habe eine sehr große Text-Datei (.txt) (rund 260MB), die ich durchsuchen will. Im wesentlichen enthält die abermillionen von Zeilen mit Messdaten und zwischendrin immer mal einige Strings wie bspw. "Frame". Nach jenen möchte ich suchen und mir die Zeile ausgeben lassen in der Sie sich befinden. Wie lange die Suche dauert bzw. wie effizient sie ist, spielt für mich keine Rolle. Obs nun 5min oder 20min dauert, völlig egal, hauptsache ich muss nichts per Hand machen :lol:.

Der Code:

Code:
var
Dateipfad: String;
FrameNumber,i,j: Integer;
Datensatz :TStringList;
Positionen: Array of Integer;
Abstaende: Array of Integer;

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
begin
    FrameNumber:=StrToInt(Edit2.text);
    Dateipfad:=Edit1.text;
    Datensatz:=TStringList.create;
    Datensatz.LoadFromFile(Dateipfad);
    SetLength(Positionen,FrameNumber+1);

    For i:=1 To Datensatz.Count-1 Do
        Begin
           If Pos('Frame',Datensatz.Strings[i])>0 Then
           Begin
           Positionen[i]:=i;
           ListBox1.Items.Add(IntToStr(Positionen[i]));
           End;
        end;


    Datensatz.free;
end;

end.
Was ich in eurer Hilfe und im Forum schon gelesen habe, ist dass TStringList nicht grad die effizienteste und eleganteste Lösung ist, aber die am einfachsten verständliche und das reicht mir vollkommen. Nun zum Problem: Der Code funktioniert bei kleineren Dateien einwandtfrei, bspw bei 15MB. Bei den großen kommt immer eine Fehlermeldung nach gewisser Zeit, warum weiss ich nicht. Wenn die Fehlermeldung kommt wird das Programm im Arbeitsspeicher RIESIG...das nimmt erst alle paar Sekunden um ca 50MB zu, bis die Größe der Text-Datei erreicht ist + Eigengröße. Dann tut sich eine Zeit lang nichts und dann explodiert die Größe im RAM auf etwas über 1GB und dann kommt der error: "Access violation". Ich nutze Lazarus, hoffe das ist im Delphi-Forum kein Problem.


Wäre wirklich froh, wenn mir jemand helfen könnte.

MfG

Peter


P.S.: Das Problem hängt nicht vom OS ab, tritt bei Win7 und WinXP auf.

implementation 9. Jan 2012 16:08

AW: Problem mit großer Textdatei
 
Wenn du über eine TStringList eine Datei lädst, dann liegt diese natürlich komplett im Speicher.
Ist die Datei also 2 GiB groß, sind damit auch 2 GiB RAM gleich weg.
Um solche gewaltigen Größen zu verarbeiten, solltest du immer nur einen Teil der Datei im Speicher halten.
Dies ginge bspw. mit
Delphi-Quellcode:
TFileStream
,
Delphi-Quellcode:
System.Text
(=SysUtils.TextFile, aber <>SysUtils.Text, aufpassen!) oder
Delphi-Quellcode:
file of char
.
Diese kannst du nun Zeile für Zeile auslesen, und jede Zeile einzeln durchsuchen.

[EDIT]
Btw., willkommen in der DP!

Bummi 9. Jan 2012 16:08

AW: Problem mit großer Textdatei
 
Streams, oder in Deinem Fall etwas in der Art:
Delphi-Quellcode:
var
  f:TextFile;
  s:String;
begin
  AssignFile(f,<DateiMitPfad>);
  Reset(f);
  while not EOF(f) do
    begin
    Readln(f,s);
    TuWas;
    end;
 CloseFile(f);
end;

Sir Rufo 9. Jan 2012 16:09

AW: Problem mit großer Textdatei
 
Beim nächsten Mal bitte die Delphi-Tags nutzen :)

Delphi-Quellcode:
var
  Dateipfad :        String;
  FrameNumber, i, j : Integer;
  Datensatz :        TStringList;
  Positionen :       Array of Integer;
  Abstaende :        Array of Integer;

  { TForm1 }

procedure TForm1.Button1Click( Sender : TObject );
begin
  FrameNumber := StrToInt( Edit2.text );
  Dateipfad  := Edit1.text;
  Datensatz  := TStringList.Create;
  Datensatz.LoadFromFile( Dateipfad );
  SetLength( Positionen, FrameNumber + 1 );

  For i := 1 To Datensatz.Count - 1 Do
    Begin
      If Pos( 'Frame', Datensatz.Strings[i] ) > 0
      Then
        Begin
          Positionen[i] := i; // hier könnte ein Überlauf passieren, wenn i > FrameNumber
          ListBox1.Items.Add( IntToStr( Positionen[i] ) );
        End;
    end;

  Datensatz.Free;
end;

end.
  1. Du prüfst niemals nach, ob das Array Positionen noch Platz hat
  2. Das Array hat beim Befüllen "Löcher", da ja wohl nicht in jeder Zeile das Wort "Frame" zu finden ist
  3. Das Befüllen der ListBox dauert hier auch seine Zeit, da bei jedem Einfügen die ListBox wieder neu gezeichnet wird
    Abhilfe schafft
    Delphi-Quellcode:
    ListBox.Items.BeginUpdate;
    try
      // ListBox mit allem Möglichen füllen
    finally
      ListBox.Items.EndUpdate;
    end;

Klaus01 9. Jan 2012 16:12

AW: Problem mit großer Textdatei
 
Hallo,

du könntest die Datei auch zeilenweise durchgehen.
Delphi-Quellcode:
var
  data: Textfile;
  i : Integer;
  s : ansiString;

begin
 ..
 Assign(datei,'dateiname');
 reset(datei);
 i:=0;

 while not eof(datei) do
   begin
     readLn(datei,s),
     inc(i);
     if {frame in s enthalten} then
       begin
         // tuwas
       end;
   end;
  close(datei);
end;
Grüße
Klaus

p80286 9. Jan 2012 16:16

AW: Problem mit großer Textdatei
 
[QUOTE=PeSch;1145074]
Delphi-Quellcode:
    SetLength(Positionen,FrameNumber+1);

    For i:=1 To Datensatz.Count-1 Do
        Begin
           If Pos('Frame',Datensatz.Strings[i])>0 Then
           Begin
           Positionen[i]:=i;
           ListBox1.Items.Add(IntToStr(Positionen[i]));
           End;
        end;
Wofür das gut sein soll,verstehe ich nicht.
Du hast eine FrameNumber, die Du nutzt um die Größe von Postionen zu definieren.

Dann trägst Du in Positionen die Zeilennummer ein, in der "Frame" gefunden wurde.
Da wäre es wesentlich sinnvoller
Delphi-Quellcode:
SetLength(Positionen,Datensatz.Count);
zu verwenden.

Und warum löschst Du die Zeilen die "Frame" enthalten nicht gleich?
Delphi-Quellcode:
for i:=Datensatz.Count-1 downto 0 do
  if pos('Frame',Datensatz[i])>0 then Datensatz.Delete[i];
Gruß
K-H

Roter Kasten auf Urlaub in Österreich?

generic 9. Jan 2012 16:31

AW: Problem mit großer Textdatei
 
Willst du das unbedingt programmieren?

Wenn nicht, dann schau dir mal das Programm GREP an.
Gibt es auch für Windows!

PeSch 9. Jan 2012 18:11

AW: Problem mit großer Textdatei
 
Hallo Leute,


Vielen Dank für die Vielen Antworten, das ging ja blitzschnell :-D.

@K-H:
Vielleicht erstmal zur Erklärung woher das ganze kommt: Also die Anzahl der "Frames" ist mir bekannt, löschen will ich sie erst in einem zweiten Schritt mit einem weiteren Button (aber vielen Dank für den Code, weil ich hab das bis letzte Woche per Hand gemacht, und das ist echt nervig :-D:-D:-D:-D:-D:-D). Der Ursprung des Ganzen ist eine CAD PIC Plasmasimulation. Diese erzeugt nach jedem Zeitschritt (Frame) eine Tabelle von ca 20*250.000 Positionen und Geschwindigkeiten. In dieser Tabelle sind die Zeitschritte eben durch das Wort "Frame" getrennt. Warum ich die Positionen der ZEILEN wissen möchte: Leider sind nicht alle Frames gleich lang. Nach einer gewissen Zeit verlassen einige der Macropartikel die Numerical Domain der Simulation und somit ändert sich die Anzahl der noch vorhandenen Teilchen pro Frame. Um eine Teilchentrajektorie in der Liste verfolgen zu können muss aber die Länge jedes Frames bekannt sein (= Differenz der Positionsnummern zweier aufeinanderfolgender Frames). Daher der ganze Aufwandt.

@generic:
Programmieren wollte ich das selbst, weil ich dann noch sehr vieles andere im Programm implementieren kann (Analytische Modell etc.) und es kann ja nicht schaden, ein wenig Programmieren zu üben (bin ziemlich eingerostet seit der Schule).

Zurück zur Sache:
@Sir Rufo: Danke schön, werde den Code morgen optimieren.

@Klaus und Bummi:
Das könnte funktionieren, werde ich gleich morgen mal ausprobieren! Vielen Dank! (soweit ich das sehen kann habt ihr ja ziemlich genau das gleiche vorgeschlagen, das wäre denke ich die sauberste Lösung von allen). Ich hatte auch mal überlegt das so ähnlich zu machen (hatte das in der Forumssuche gefunden) war nur nicht ganz sicher ob das Zeilenbehaftet funktioniert, sprich: Zu Beginn hatte ich einen Stream in ein String geladen, da hat er mir aber dann die Zeichenposition gegeben, die ich natürlich nicht gebrauchen kann. Zeilenweise abtasten hört sich sehr gut an.

Ich werds mal ausprobieren und morgen melde ich mich wieder um zu berichten.

Vielen Dank!!!! :)

P.S.: Was ist eigentlich mit Delphi passiert? Ich hab das viele Jahre nicht gemacht, dann im Studium wieder gebraucht, aber gefunden habe ich nur noch Lazarus. Gibts kein Delphi mehr? Früher gabs doch dieses Personal 6 für Schüler und Studenten kostenlos.

Mit freundlichen Grüßen

Peter

PeSch 10. Jan 2012 10:32

AW: Problem mit großer Textdatei
 
Hallo Leute,

Sorry für den Doppel-Post.

Also erstmal Vielen Dank an alle, ihr habt mir sehr geholfen.

Ich habe das Programm nun so abgeändert, wie Klaus und Bummi vorgeschlagen haben und zusätzlich optimiert wie von Sir Rufo vorgeschlagen.

Es funktioniert tadellos und auch recht schnell! Ich habe das Programm dann so erweitert, dass es mir zusätzlich eine neue Datei erstellt, in der nur noch die reinen Daten vorhanden sind und alle Störzeilen wegfallen. Des weiteren erstellt das Programm auch noch eine kleine Datei in der die Intervalllängen eingetragen sind, sodass ich die da ablesen kann.

Dadurch kann ich meine Daten nun grade zu in Fliessbandarbeit auswerten :lol::lol::lol::lol:.

VIELEN DANK!!!!


Eine Anmerkung noch:
Delphi-Quellcode:
Inc()
finde ich überflüssig wie einen Kroppf. Früher ging das einfach via
Delphi-Quellcode:
i:=i+1;
...


Eine Frage hätte ich noch:

Was ist denn der gravierende Unterschied zwischen ANSISTRING und STRING? Ich hab hier im Forum irgendwo mal gelesen das wäre nur eine reine Umbennenung in neueren Versionen?!

MfG


Peter

himitsu 10. Jan 2012 10:48

AW: Problem mit großer Textdatei
 
Delphi-Quellcode:
Inc(i)
und
Delphi-Quellcode:
i:=i+1
ist das Gleiche.
Was der Programmierer nutzt, ist ihm überlassen und der Compiler optimiert am Ende alles in ein INC (Assembler).


String und Char sind keine statischen Datentypen.
Die passen sich an den Compiler die kompilierte Zielumgebung an.
Seit Delphi 2009 ist String=UnicodeString und davor AnsiString.


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:38 Uhr.
Seite 1 von 2  1 2      

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