![]() |
aus 480 MB txt Datei, bestimmte Zeilen löschen lassen...
Morgen,
mal was ganz anderes. Eine txt die 480 MB klein ist, enthält tausende Datensätze. Es handelt sich um GPS Daten, in der Form von X, Y und Z. Mal ein kleiner Auszug:
Delphi-Quellcode:
Wenn jetzt an der 31sten Stelle bis zur 35sten "-300" steht, dann muss die Reie gelöscht werden.
.00 .00 -300.00 0
6000193.27 4526048.99 53.87 51 6000193.75 4526047.31 53.87 51 6000194.24 4526045.63 53.76 69 6000194.72 4526043.96 53.82 60 6000195.20 4526042.30 53.92 43 6000195.69 4526040.61 53.84 39 6000196.17 4526038.93 53.79 39 6000196.66 4526037.26 53.79 43 6000197.14 4526035.58 53.78 47 6000197.63 4526033.90 53.81 39 .00 .00 -300.00 0 .00 .00 -300.00 0 .00 .00 -300.00 0 Meine Überlegungen sehen so aus:
Delphi-Quellcode:
Also doch sehr schlecht...
var tin, tout:Textfile;
lese:String; begin AssignFile(tin, 'c:\kai.txt'); // Name der Datei ist kai, lasse sie damit Laden AssignFile(tout, 'c:\kaineu.txt'); // gebe hier Name und Pfad an, wo das Resultat dann hin soll Reset(tin); Rewrite(tout); while not Eof(tin) do begin ReadLn(tin, lese); [...] // ab hier fehlts mir end; CloseFile(tout); CloseFile(tin); end; Wie kann man das Problem lösen? |
Re: aus 480 MB txt Datei, bestimmte Zeilen löschen lassen...
Ich habe mal so was über zwei Stringlisten gelöst.
|
Re: aus 480 MB txt Datei, bestimmte Zeilen löschen lassen...
Zitat:
|
Re: aus 480 MB txt Datei, bestimmte Zeilen löschen lassen...
Hallo LuckyStrike4life,
generell sollte der fehlende Abschnitt in etwa so lauten:
Delphi-Quellcode:
Die Frage lautet also, wie ermittelst Du, ob der String das von Dir geforderte Kriterium (DoesStringMatchCriteria) erfüllt. Generell verwende ich bei der Verarbeitung von Strings gerne [dp]reguläre Ausdrücke[/dp] in diesem Fall ist das Problem aber nicht zu letzt von der Ausführungszeit bestimmt und die Daten auch recht einfach beschaffen.
while not Eof(tin) do
begin ReadLn(tin, lese); if DoesStringMatchCriteria(lese) then WriteLn(tout); end; Ich empfehle Dir deshalb den Einsatz von Copy (Teilbereich extrahieren), Trim (Leerzeichen des ermittelten Teilbereichs entferen) und StrToIntDef bzw Val (Rest: Zahl als String in Zahl umwandeln) um die Daten zu verarbeiten. Ein letztlicher Vergleich gegen -300 bildet dann den Rückgabewert von DoesStringMatchCriteria. |
Re: aus 480 MB txt Datei, bestimmte Zeilen löschen lassen...
Hallo Luckie,
den Einsatz von Stringlisten halte ich bei der Art deren Implementierung (sofern Du TStringList meinst) bei der Dateigröße von knapp 0,5GB für gewagt (schließlich würde die Datei zunächst vollständig in den RAM geladen werden)... |
Re: aus 480 MB txt Datei, bestimmte Zeilen löschen lassen...
Zitat:
Wo liegt denn das Problem? Stringliste erstellen? |
Re: aus 480 MB txt Datei, bestimmte Zeilen löschen lassen...
Zitat:
|
Re: aus 480 MB txt Datei, bestimmte Zeilen löschen lassen...
Zitat:
Hallo LuckyStrike4life, die Idee ist schon richtig, in den Speicher sollte man so eine Datei wirklich nicht laden. das Spaltentrennzeichen ist sicherlich Tab. Guck Dir mal Stringreplace an. von jeder Spalte die einzelne Zelle überprüfen, ob negativ, dann löschen. bzw nicht neu schreiben. vielleicht hilft Dir diese kleine Funktion weiter ?
Code:
function GetStrNr(const aStr, delim: string; nr: integer): string;
begin with TStringList.Create do begin Text := StringReplace(aStr, delim, #13#10, [rfReplaceAll]); result := strings[nr - 1]; free; end; end; |
Re: aus 480 MB txt Datei, bestimmte Zeilen löschen lassen...
Zitat:
Ich selbst kenne und verwende diverse andere Implementierungen (zB aus Performancegründen oder auch, um transparent mit String-Ressourcen umzugehen). |
Re: aus 480 MB txt Datei, bestimmte Zeilen löschen lassen...
Autsch. StringReplace dürfte bei so einer Größe tödlich sein, was die Performance angeht.
|
Re: aus 480 MB txt Datei, bestimmte Zeilen löschen lassen...
Zitat:
@stoxx: Ich gehe wegen der Ausrichtung der Daten (rechtsbündig) nicht von Tabs sondern Leerzeichen aus, so dass die Spalten direkt über die Zeichenposition im String indiziert werden können und eine Lösung mit Copy & Co (s.o.) als ad hoc-Lösung (ohne Hilfsklassen) am einfachsten scheint... |
Re: aus 480 MB txt Datei, bestimmte Zeilen löschen lassen...
@stoxx
leider sind es Leerzeichen, wurden nicht mit Tabulator gemacht. Wenn du dein Code vielleicht n wenig erklären magst? Also besser nicht mit Strings? Was würde mir denn bleiben? |
Re: aus 480 MB txt Datei, bestimmte Zeilen löschen lassen...
Zitat:
hab ich noch nicht mit gearbeitet... du meinst das vermutlich in etwa so:
Delphi-Quellcode:
dann müsste jetzt ne Abfrage her, die schaut ob das eingelesene -300 ist, oder nicht...
begin
AssignFile(tin, 'c:\kai.txt'); AssignFile(tout, 'c:\kaineu.txt'); Reset(tin); Rewrite(tout); while not Eof(tin) do begin ReadLn(tin, lese); WriteLn(tout, Copy(lese, 31, 5) // ich lasse so von Zeichen 31 - 5 Zeichen weiter lesen |
Re: aus 480 MB txt Datei, bestimmte Zeilen löschen lassen...
Zitat:
Delphi-Quellcode:
mit der Funktion DoesStringMatchCriteria, die entscheidet, ob ein String der Ausgaben angehängt werden soll, oder nicht. Nach der Beschreibung (dritte Spalte <>'-300.00') und dem gegebenen Ausschnitt (zwei führende Spaces) könnte diese Funktion so aussehen:
while not Eof(tin) do
begin ReadLn(tin, lese); if DoesStringMatchCriteria(lese) then WriteLn(tout); end;
Delphi-Quellcode:
Wenn Dich später doch der Zahlenwert oder eine andere Spalte (also auch Werte, die länger oder kürzer sind und an anderen Stellen liegen können) könntest Du die zuerst beschriebene Lösung wählen...
function DoesStringMatchCriteria(const AString: string): Boolean;
const ColStart = 32; ColWidth = 7; begin Result:= Copy(AString, ColStart, ColWidth) <> '-300.00'; end; |
Re: aus 480 MB txt Datei, bestimmte Zeilen löschen lassen...
Hallo!
3 Varianten sind möglich: 1. die zu löschenden Zeilen haben alle denselben Inhalt. Dann sieht das Ganze so aus:
Delphi-Quellcode:
Deine Beispieldaten sind ja so aufgebaut.
const loeschen = ' .00 .00 -300.00 0';
var tin, tout:Textfile; lese:String; begin AssignFile(tin, 'c:\kai.txt'); // Name der Datei ist kai, lasse sie damit Laden AssignFile(tout, 'c:\kaineu.txt'); // gebe hier Name und Pfad an, wo das Resultat dann hin soll Reset(tin); Rewrite(tout); while not Eof(tin) do begin ReadLn(tin, lese); if lese <> loeschen then // Vergleich der kompletten Zeile writeln(tout,lese); end; CloseFile(tout); CloseFile(tin); end; 2. die zu löschenden Zeilen haben unterschiedlichen Inhalt, aber die Spalten sind fest definiert. Dann sieht das Ganze so aus:
Delphi-Quellcode:
const loeschen = '-300.00';
loeschpos=32; // ggf. auszählen! var tin, tout:Textfile; lese:String; begin AssignFile(tin, 'c:\kai.txt'); // Name der Datei ist kai, lasse sie damit Laden AssignFile(tout, 'c:\kaineu.txt'); // gebe hier Name und Pfad an, wo das Resultat dann hin soll Reset(tin); Rewrite(tout); while not Eof(tin) do begin ReadLn(tin, lese); if Copy(lese,loeschpos,Length(loeschen)) <> loeschen then // Vergleich der betreffenden Spalten writeln(tout,lese); end; CloseFile(tout); CloseFile(tin); end; 3. die zu löschenden Zeilen enthalten das "-300.00" an unterschiedlichen Stellen, aber dieser Wert kommt in den übrigen Zeilen garantiert nicht vor. Dann sieht das Ganze so aus:
Delphi-Quellcode:
Sollte keines der Kritereien erfüllt sein, mußt Du eben die Zeile zerlegen und dann den passenden Abschnitt (hier 3. Bereich) vergleichen.
const loeschen = '-300.00';
var tin, tout:Textfile; lese:String; begin AssignFile(tin, 'c:\kai.txt'); // Name der Datei ist kai, lasse sie damit Laden AssignFile(tout, 'c:\kaineu.txt'); // gebe hier Name und Pfad an, wo das Resultat dann hin soll Reset(tin); Rewrite(tout); while not Eof(tin) do begin ReadLn(tin, lese); if Pos(loeschen,lese) <> 0 then // KO-Zeichenfolge suchen writeln(tout,lese); end; CloseFile(tout); CloseFile(tin); end; Allerdings gebe ich eines zu bedenken: Auch wenn es sehr ressourcenfressend ist, nach Windows-Norm muss die komplette Datei in den Speicher. Wozu gibt es das Pagefile - auch wenn das das System ausbremst :mrgreen: Ich bevorzuge allerdings auch die klassische Methode mit zeilenweiser Verarbeitung. Gruß Dietmar Brüggendiek |
Re: aus 480 MB txt Datei, bestimmte Zeilen löschen lassen...
Hallo Dietmar,
eine gute Darstellung! Wahrscheinlich ist das Kriterium "dritte Spalte -300" tatsächlich eher so zu verstehen, wie Deine erste Variante prüft, was sehr elegant im Code aussieht ("Wenn Zeile so aussieht wie eine zu löschende") :) Zitat:
|
Re: aus 480 MB txt Datei, bestimmte Zeilen löschen lassen...
Hallo!
Zitat:
Außerdem ist das ja wohl auf mehrere Dateien aufgeteilt, die nacheinander geladen werden :mrgreen: Gruß Dietmar Brüggendiek |
Re: aus 480 MB txt Datei, bestimmte Zeilen löschen lassen...
Brüggendiek´
Danke! Variante 1 war die richtige!! Jetzt kommt der große Test mit der Großen Datei aufm Server ;). Auch an alle anderen vielen Dank!! |
Re: aus 480 MB txt Datei, bestimmte Zeilen löschen lassen...
Bei so großen Dateien würde ich es vermeiden die neuen Daten in eine Zweite zu kopieren.
Man könnte die Datei auch Binäry betrachten.
Delphi-Quellcode:
Vorsicht: Aus der kalten getippt!
var iMove : Integer; // Gibt an um wieviel Bytes eine Zeile vorkopiert werden soll
stm := TFileStream.Create(...); iMove := 0; while stm.Size > stm.Position do begin sLine := ReadLine(stm); if MatchDel(stm) then begin Inc(iMove, Length(sLine)); Inc(iMove, 2); // CRLF end else begin stm.Seek(soFromCurrent, -iMove); stm.Write(PChar(sLine)^, Length(sLine)); stm.Write(cCRLF, 2); stm.Seek(soFromCurrent, iMove); end; end; |
Re: aus 480 MB txt Datei, bestimmte Zeilen löschen lassen...
Zitat:
Egal ob 10 GByte oder mehr. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:47 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-2025 by Thomas Breitkreuz