![]() |
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:
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.
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; 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:
...bekomme ich zurecht einen Fehler, da die Textdatei mit Reset() nur für das Lesen geöffnet wird.
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); 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!? |
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. |
AW: Große Textdatei - einzelne Zeile löschen
Zitat:
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 |
AW: Große Textdatei - einzelne Zeile löschen
Check doch erstmal, ob das Lesen der Datei der Bottleneck ist oder das Schreiben der Einzeldateien.
|
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?
|
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: ![]() Flamefire hat sich das angeschaut und das ganze mit Streams umgesetzt: ![]() Für die beste Performance musst du da vielleicht noch ein wenig schrauben, aber zumindest siehst du dort wie du mit MMFs arbeiten kannst. |
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.
|
AW: Große Textdatei - einzelne Zeile löschen
Ich hatte mal
![]() 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. |
AW: Große Textdatei - einzelne Zeile löschen
Zitat:
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. |
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:19 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