Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Große Textdatei - einzelne Zeile löschen (https://www.delphipraxis.net/211189-grosse-textdatei-einzelne-zeile-loeschen.html)

GummiKuh68 10. Aug 2022 14:36

Große Textdatei - einzelne Zeile löschen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Moin, moin,

...'...oh Nein, nicht schon wieder Textdatei...' möge manch einer jetzt denken...hatten wir schon!
Ja und habe ich auch alles gelesen - passt aber alles nicht!

Problem:
Ich habe eine Datei die ca. 97 GB groß ist (Klartext: rockyou2021.txt!).
Eins vorneweg - das Problem mit ähnlich großen Dateien habe ich auch während des Supports, wenn ich Messdaten im Rahmen der Fehlersuche analysieren muss.

Nun ist es ja so, dass man Dateien ab einer gewissen Größe nicht mal ebenso in einen Editor laden kann.
Notepad++, PilotEdit, PSPad, usw. machen da irgendwann schlapp! UltraEdit soll das angeblich können, aber da der Download der Demo nicht klappt, kann ich dazu wenig sagen! :roll:

Meine Idee war nun, Zeile für Zeile aus der Datei zu lesen und gleich in eine andere Datei zu schreiben, deren Dateiname sich vom Original unterscheidet (Zusatz im Dateinamen: ASCII-Wert des ersten Zeichens!).
Das habe ich auch schon hinbekommen, dass läuft sauber durch.
Das Dumme daran ist, das ich dafür den Rechner die nächste Tage durchlaufen lassen muss - wenn ich das mache, habe ich gleich GAAAAANNZZ andere Probleme! :shock:

Aktuell benutze ich folgenden Code:

Delphi-Quellcode:
procedure TForm1.cb3Click(Sender: TObject);
var
  InFile : TextFile;
  i,cnt,s : integer;
  Rest,a: string;
  b      :Char;
begin
  assignFile (Infile, 'I:\rockyou2021.txt');
  reset (Infile);
  while not eof (InFile) do
    begin
      readln (InFile, Rest);
      if Rest <> '' then
        begin
          b:=Rest[1];
          of_insstr('I:\rockyou2021-'+inttostr(ord(b))+'.txt',Rest);
        end;
    end;
  CloseFile (InFile);
end;

procedure TForm1.of_insstr(OFile,fstr:string);
var
  OutFile :TextFile;
  i,cnt,s : integer;
  Rest,a,b: string;
begin
  //
  if FileExists(OFile) then
    begin
      assignFile (OutFile, OFile);
      append(OutFile);
    end
  else
    begin
      assignFile (OutFile, OFile);
      rewrite(OutFile);
    end;
  Writeln(OutFile,fstr);
  CloseFile (OutFile);
end;
Ich hab das jetzt auch schon mal laufen lassen und war auch mit dem Ergebnis bisher zufrieden. Allerdings werde ich das wegen der Dauer (habe nach 4 Stunden abgebrochen), immer wieder neu starten müssen.
Das bedeutet aber, das das Programm die Datei von Anfang an ließt und wenn ich die erzeugten Dateien nicht wegschmeiße, alles doppelt reinschreibt, was Mist ist!

Daher war meine Idee, dass ich die Zeile, die ich gerade in eine andere Datei geschrieben habe aus der Ursprungsdatei lösche.
Wenn ich den Code in cb3Click jetzt wie folgt anpasse:

Delphi-Quellcode:
  assignFile (Infile, 'I:\rockyou2022.txt');
  reset (Infile);
  while not eof (InFile) do
    begin
      readln (InFile, Rest);
      if Rest <> '' then
        begin
          b:=Rest[1];
          of_insstr('I:\rockyou2021-'+inttostr(ord(b))+'.txt',Rest);
          writeln(InFile, ''); // '' wäre ok, obwohl noch #13#10 bleibt! Ganz raus wäre noch besser!
        end;
    end;
  CloseFile (InFile);
...bekomme ich zurecht einen Fehler, da die Textdatei mit Reset() nur für das Lesen geöffnet wird.

Was übersehe ich hier?

Ich hatte schon über TStringList nachgedacht aber wenn ich die ca. 97 GB da reinlade...??

TFileStream hatte ich auch schonmal als Idee im Hinterkopf, aber keinen Plan, da ich mit FileStreams bisher eher weniger zu tun hatte.
Zum Testen habe ich mir natürlich eine kleinere Datei gebastelt (s. Anhang).

Vielleicht hat da ja jemand von euch eine Idee!?

Rollo62 10. Aug 2022 20:20

AW: Große Textdatei - einzelne Zeile löschen
 
Also gefühlt würde ich sagen dass ein zeilenweises Einlesen da nicht ganz optimal ist.
Hast Du mal versucht das Ganze blockweise einzulesen, z.B. 64K Blöcke oder mehr, und die dann im Speicher zu analysieren und blockweise zurückzuschreiben ?
Das ist zwar wesentlich komplexer, aber ich denke das lohnt sich geschwindigkeitsmäßig.

himitsu 10. Aug 2022 20:53

AW: Große Textdatei - einzelne Zeile löschen
 
Zitat:

Was übersehe ich hier?
Daß du zwei Dateien brauchs? (Lesen + Schreiben)

Selbst wenn du vor/nach dem Lesen/Schreiben die Stream-Position "zurück"-setzt,
bekommst du Probleme, wenn die geschriebene Zeile länger ist, als die Gelesene, weil du damit ja bereits die nächste Zeile überschreibst, welche du noch garnicht gelesen hast.

Mit passenden Sharing-Rechten, kann man die gleiche Datei auch mehrmals öffnen, also Lesen und nochmal zum Schreiben.
Aber kann man auch mit nur einem File-Handle und zwei Cursor-Positionen.


Wobei es hier ginge, da Schreiben kürzer ist, als Lesen. (Zeile>'' lesen und Zeile='' schreiben)
Aber nein, SO kannst du keine Zeile löschen, denn die nachfolgenden Zeilen bleiben dennoch an der selben Stelle, was DU selbst verschieben müsstest.
Würdes du die Zeile mit einem '' löschen überschreiben, bliebe der Rest der alten Zeile dennoch erhalten (man könnte diese Zeile höchstsen in der selben Länge z.B. mit mehreren #0 oder ' ' überscheiben, ohne Nachfolgendes verschieben zu müssen)
Code:
** = Zeilenumbruch
_  = Leerzeichen, #0 oder sonstwas

Zeile1**Zeile2**Zeile3**Zeile4** ~ Original

NeueZeile1**e2**Zeile3**Zeile4** ~ Zeile1** durch NeueZeile1** überschrieben (Zeile2** nicht mehr lesbar)
xx**e1**Zeile2**Zeile3**Zeile4** ~ Zeile1** durch xx** überschrieben
**ile1**Zeile2**Zeile3**Zeile4** ~ Zeile1** durch ** überschrieben, aka WriteLn('')

______**Zeile2**Zeile3**Zeile4** ~ Zeile1** durch ______** überschrieben
________Zeile2**Zeile3**Zeile4** ~ Zeile1** durch ________ überschrieben
********Zeile2**Zeile3**Zeile4** ~ Zeile1** durch ******** überschrieben, also 4 Mal WriteLn(''), aber bei ungerader Länge hast'e ein kleines Problem
Zeile2**Zeile3**Zeile4**         ~ Zeile1** gelöscht und Nachfolgendes verschoben (schnell wird es so aber nicht ... weil ja massenhaft Speicher mehrmals verschoben wird)


WriteLn ohne #13#10 heißt Write :roll:




TStringList oder TStringStream
und notfalls als 64 Bit kompilieren (ja, neuere Delphis haben ein paar Vorteile)

Auch wenn eine 100M Datei vermutlich ebenfalls in 32 Bit funktioniert.
Man darf aber bedenken, dass der Speicherverbauch beim Laden/Speichern auch mal vorübergehend das 5-fache belegen kann, aber 500M passen ja noch. (5 bei Unicode, aber 2- bis 3-faches auch schon im D7 mit ANSI)




* "nutzlos" zu speichern/überschreiben macht es langsamer
* die alten "Pascal"-Textdatei-Funktionen arbeiten mit einem sehr unoptimalen Buffering = langsam
* TStringList ist nicht ganz optimal und braucht mehr Arbeitsspeicher, aber dennoch ist es viel schneller

* of_insstr sucht und öffnet/speichert immer wieder Dateien = langsam
* * die Dateien (FileHandles) sich zu merken und erst am Ende zu schließen wäre schneller (sind ja nur etwa 60 bis 255 Dateien)
* * oder die QuellDatei mehrmals durchlaufen und jeweils nur EINE "of_insstr"-Datei du behandeln ... zwar mehrmals Lesen aber immer nur jeweils eine Ausgabedatei in einem Rutsch

Uwe Raabe 10. Aug 2022 20:57

AW: Große Textdatei - einzelne Zeile löschen
 
Check doch erstmal, ob das Lesen der Datei der Bottleneck ist oder das Schreiben der Einzeldateien.

Der schöne Günther 10. Aug 2022 21:03

AW: Große Textdatei - einzelne Zeile löschen
 
Ist es schon zu spät für mich, oder machst du bei jeder einzelnen Zeile deine Zieldatei auf und wieder zu?

jaenicke 10. Aug 2022 21:09

AW: Große Textdatei - einzelne Zeile löschen
 
Ich würde hier mit MMFs arbeiten. Durch das Mapping in den Arbeitsspeicher ist das extrem schnell. Damals kam ich bei einer normalen Festplatte auf 84 MiB/s, was heute mit einer SSD noch viel schneller gehen sollte.

Ich habe dafür einen Wrapper geschrieben:
https://www.delphipraxis.net/151898-...ei-reader.html

Flamefire hat sich das angeschaut und das ganze mit Streams umgesetzt:
https://entwickler-ecke.de/viewtopic.php?t=100088

Für die beste Performance musst du da vielleicht noch ein wenig schrauben, aber zumindest siehst du dort wie du mit MMFs arbeiten kannst.

Monday 11. Aug 2022 06:41

AW: Große Textdatei - einzelne Zeile löschen
 
Kannst du mal bei Notepad++ das Plugin "BigFiles - Open Very Large Files" probieren? Würde mich interessieren, ob er das packt.

dummzeuch 11. Aug 2022 08:02

AW: Große Textdatei - einzelne Zeile löschen
 
Ich hatte mal ein Tool zum Anschauen großer Textdateien geschrieben, das ich damals mit einem Dump der Wikipedia getestet hatte (damals 48 GB).

Funktionsweise war, dass es in einem Hintergrund-Thread die Datei liest und einen Index der Zeilenumbrüche bzw. Zeilenanfänge erzeugt, den es in eine Datei schreibt, so dass der Index nicht jedes Mal neu erzeugt werden muss.

Vielleicht findest Du ja im Sourcecode ein paar Anregungen?

Wichtig: Die Suchfunktion habe ich nie fertiggestellt, nicht dass Du dich wunderst, dass sie nicht funktioniert.

freimatz 11. Aug 2022 08:54

AW: Große Textdatei - einzelne Zeile löschen
 
Zitat:

Zitat von GummiKuh68 (Beitrag 1509976)
Nun ist es ja so, dass man Dateien ab einer gewissen Größe nicht mal ebenso in einen Editor laden kann.
Notepad++, PilotEdit, PSPad, usw. machen da irgendwann schlapp! UltraEdit soll das angeblich können, aber da der Download der Demo nicht klappt, kann ich dazu wenig sagen! :roll:

Mal hier versucht Ultraedit, neueste Version, aber nur 50GByte und keine Textdatei sondern binär.
a) Nach einigen Minuten war er bei 50%, habe dann abgebrochen
b) Eine Option umgestellt, nochmals versucht, nach ca. 2 Sekunden war die Datei da.
Scrollen über die ganze Datei ist etwas hackelig, finde ich aber erstaunlich gut.

jaenicke 11. Aug 2022 09:03

AW: Große Textdatei - einzelne Zeile löschen
 
Ich würde das schlicht mit HxD machen, wenn es ein fertiges Programm sein soll. Dann fällt einiges weg, was ein Texteditor noch zusätzlich machen muss, und es muss wirklich nur die Änderung an der Datei geschrieben werden.


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:44 Uhr.
Seite 1 von 3  1 23      

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