80 MB Datei - doppelte Zeilen entfernen
Hallo,
ich muss bei einer 80 MB großen Datei alle doppelten un leeren Zeilen entfernen So dauert das eine Ewigkeit:
Delphi-Quellcode:
gruss vom capo
if FileExists('logfile.txt') then
begin FWords := THashedStringList.Create; application.ProcessMessages; FWords.LoadFromFile( ExtractFilePath(Application.ExeName) + 'logfile.txt'); lv.Items.Count := FWords.Count; DeleteDuplicates(Fwords); |
Re: 80 MB Datei - doppelte Zeilen entfernen
Wie sieht das Format einer Zeile aus?
|
Re: 80 MB Datei - doppelte Zeilen entfernen
Besorg dir AQTime und such die Hotspots der verbratenen Zeit
|
Re: 80 MB Datei - doppelte Zeilen entfernen
Hallo, einen Ansatz dazu findest Du hier
|
Re: 80 MB Datei - doppelte Zeilen entfernen
Zitat:
Hast Du 160MB Platz? Dann so:
Delphi-Quellcode:
Untested...QuickandDirty.. NoErrorcheck
var
fd1,fd2 : Textfile; S,Last : string; begin assignfile(fd1,'logfile.txt'); assignfile(fd2,'logfile.neu'); reset(fd1); rewrite(fd2); Last := ''; while not(eof(fd1)) do begin readln(fd1,S); if (trim(S)<>'') and (S <> LAST) then writeln(fd2,S); Last := S; end; Closefile(fd2); Closefile(fd1); deletefile(fd1); rename(fd2,'logfile.txt'); end; Schreibmal wieviel schneller es war! Frank :coder: |
Re: 80 MB Datei - doppelte Zeilen entfernen
Hi,
wie arbeitet denn die Methode DeleteDuplicates? Und wie meinst Du denn doppelte Zeilen? Möchtest Du hier Zeilen die zweimal hintereinander stehen entfernen? Oder möchstest Du die Datei in disjunkte Zeilen zerlegen (also eine Zeile wird nur einmal in die Liste übernommen, egal wie oft und wo sie in der Datei vorkommt)? Gruß Der Unwissende |
Re: 80 MB Datei - doppelte Zeilen entfernen
Hallo
danke für eure Antworten. Die zeilen können auch 2 - x mal vorkommen, habe meine Frage falsch formulieren. Das hier scheint dann dafür nicht das richtige zu sein, oder.
Delphi-Quellcode:
hier habe ich dann auch noch einen fehler:
var
fd1,fd2 : Textfile; S,Last : string; begin assignfile(fd1,'logfile.txt'); assignfile(fd2,'logfile.neu'); reset(fd1); rewrite(fd2); Last := ''; while not(eof(fd1)) do begin readln(fd1,S); if (trim(S)<>'') and (S <> LAST) then writeln(fd2,S); Last := S; end; Closefile(fd2); Closefile(fd1); deletefile(fd1); rename(fd2,'logfile.txt'); end; Zitat:
Delphi-Quellcode:
deletefile(fd1);
|
Re: 80 MB Datei - doppelte Zeilen entfernen
Zitat:
Delphi-Quellcode:
deletefile('logfile.txt');
|
Re: 80 MB Datei - doppelte Zeilen entfernen
Sorry doch, dass ist genau das richtige...
Muss nur
Delphi-Quellcode:
heißen..
delete(fd1);
Frank :coder: |
Re: 80 MB Datei - doppelte Zeilen entfernen
Hallo
so mach ich das nun aber es sind immer noch doppelte Einträge vorhanden. Also dachte ich mir lass ich das ganze nocheinmal mit der neuen Datei durchlaufen, klappt aber dennoch nicht:
Delphi-Quellcode:
gruss capo
procedure TForm1.Button1Click(Sender: TObject);
var fd1,fd2 : Textfile; S,Last : string; begin assignfile(fd1,'C:\logfile.txt'); assignfile(fd2,'C:\logfile.neu'); reset(fd1); rewrite(fd2); Last := ''; while not(eof(fd1)) do begin readln(fd1,S); if (trim(S)<>'') and (S <> LAST) then writeln(fd2,S); Last := S; end; Closefile(fd2); Closefile(fd1); deletefile('logfile.txt'); rename(fd1,'C:\logfile.txt'); end; |
Re: 80 MB Datei - doppelte Zeilen entfernen
Zitat:
Delphi-Quellcode:
So, damit hast Du dann die Variante, die alle aufeinander folgenden, gleichen Zeilen löscht.
while not(eof(fd1)) do
begin readln(fd1,S); if (trim(S)<>'') and (S <> LAST) then begin writeln(fd2,S); Last := S; end; end; Möchtest Du allgemeiner jede Zeile nur einmal haben, dann versuche es lieber mit:
Delphi-Quellcode:
Wie Du hier siehst, wird der Hash nur für die neue Liste verwendet, die alte sollte möglichst keinen haben, da Du hier eh alle Zeilen betrachten wirst. Das Berechnen eines Hashs bringt dir also keinen Vorteil, kostet aber Zeit. Wird nun nach dem Index eines Strings gesucht, so kann dies mit einem Hash sehr viel schneller durchgeführt werden als ohne, für die neue Liste lohnt sich also dieser Hash. Alternativ gibt es noch mind. zwei Möglichkeiten, Du kannst die HashedStringList auch durch eine Map (Alzaimar hat mal eine für Strings als Schlüssel zur Verfügung gestellt) ersetzen (die ist vielleicht noch schneller). Oder aber du setzt bei der neuen StringList die Eigenschaft sorted auf True und die Eigenschaft Duplicates auf dupIgnore. Was davon die höchste Perfomance erzielt kann ich so nicht sagen, musst Du einfach mal testen.
var listAlt, listNeu: TStringList;
i: Integer; begin listAlt := TStringList.Create; // laden wie gehabt listAlt.LoadFromFile('...'); listNeu := THashedStringList.Create; for i := 0 to listAlt.Count - 1 do begin if listNeu.indexOf(listAlt[i]) < 0 then begin listNeu.add(listAlt[i]); end; end; listNeu.SaveToFile('...'); end; Gruß Der Unwissende |
Re: 80 MB Datei - doppelte Zeilen entfernen
Zitat:
Wer will schon aus einen Logfile alle doppelten killen? Oder ist das so.. Frank |
Re: 80 MB Datei - doppelte Zeilen entfernen
Zitat:
ggf. mal
Delphi-Quellcode:
Frank
procedure TForm1.Button1Click(Sender: TObject);
var fd1,fd2 : Textfile; S,Last : string; begin assignfile(fd1,'C:\logfile.txt'); assignfile(fd2,'C:\logfile.neu'); reset(fd1); rewrite(fd2); Last := ''; while not(eof(fd1)) do begin readln(fd1,S); if (trim(S)<>'') and (uppercase(S) <> LAST) then begin writeln(fd2,S); Last := uppercase(S); end; end; Closefile(fd2); Closefile(fd1); delete(fd1); rename(fd1,'C:\logfile.txt'); end; |
Re: 80 MB Datei - doppelte Zeilen entfernen
Zitat:
Aber selbst im Log-File, wenn Du nur sehen möchtest, was für Probleme aufgetreten sind... Also es gibt bestimmt Dateien, wo man sich einfach mal die disjunkten Zerlegungen anschauen möchte. Aber mal die Frage andersrum, welches Logfile speichert denn mehrfach aufeinander folgend exact die gleiche Zeile? (schon wenn Datum und Uhrzeit im Log vorkommen hat man hier ja schnell zwei unterschiedliche Strings). |
Re: 80 MB Datei - doppelte Zeilen entfernen
Na ich würde sagen:
Delphi-Quellcode:
Sieht mir sehr nach einem Logfile aus...
if FileExists('logfile.txt') then
Frank |
Re: 80 MB Datei - doppelte Zeilen entfernen
Zitat:
Ok, ich fang an und lerne Lesen! Ihr habt's ja so gewollt! |
Re: 80 MB Datei - doppelte Zeilen entfernen
Logfile.txt heisst die Datei nur weil ich den Code aus einem anderen Programm von mir übernommen habe.
Es sind Adressen um die es geht. gruss capo |
Re: 80 MB Datei - doppelte Zeilen entfernen
Delphi-Quellcode:
damit läuft es nun schon eine stunde, nichts passiert
var listAlt, listNeu: TStringList;
i: Integer; begin listAlt := TStringList.Create; // laden wie gehabt listAlt.LoadFromFile('...'); listNeu := THashedStringList.Create; for i := 0 to listAlt.Count - 1 do begin if listNeu.indexOf(listAlt[i]) < 0 then begin listNeu.add(listAlt[i]); end; end; listNeu.SaveToFile('...'); end; |
Re: 80 MB Datei - doppelte Zeilen entfernen
Moin Capo,
bist Du sicher, dass das Programm überhaupt schon mit dem Einlesen der Datei fertig ist? 80MB in eine Stringlist einzulesen kann ziemlich dauern. Wenn Du wirklich nur doppelte Zeilen finden willst, halte ich es für sinnvoller die Datei zeilenweise zu lesen (ReadLn usw.), jeweils einen MD5-Hash über der Zeile zu bilden, diesen in einer STringList suchen. Ist er nicht vorhanden, die Zeile in eine Zieldatei wegschreiben, und den Hashwert mit in die Tabelle aufnehmen. Die Eigenschaft Capacity (Anzahl zu erwartender Zeilen) einer StringList solltest Du bei solchen Aktionen auf einen möglichst korrekten Wert einstellen, um Geschwindigkeit herauszuholen. |
Re: 80 MB Datei - doppelte Zeilen entfernen
Moin Christian,
wäre es nicht schneller, die Strings direkt zu vergleichen, statt erst den "Umweg" per MD5 zu gehen ? Gruß |
Re: 80 MB Datei - doppelte Zeilen entfernen
Zitat:
|
Re: 80 MB Datei - doppelte Zeilen entfernen
hallo und danke für eure antworten.
habs nun so gelöst: dauert damit ca. 10 minuten merkwürdigerweise werden dabei auch einige ; in der datei gelöscht. insofern ist diese lösung doch nicht so geeignet.
Delphi-Quellcode:
hallo Christian
procedure TForm1.Button1Click(Sender: TObject);
var SL: TStringList; I: integer; begin SL := TStringList.Create; try SL.BeginUpdate; try SL.LoadFromFile('C:\file.txt'); SL.Sort; for i := SL.Count - 2 downto 0 do if SL[i] = SL[i + 1] then SL.Delete(i + 1); SL.SaveToFile('C:\file_ok.txt'); finally SL.EndUpdate; end; finally SL.Free; end; Showmessage('Fertig...'); end; hast du evt. ein beispiel, ein paar zeilen? gruss capo |
Re: 80 MB Datei - doppelte Zeilen entfernen
Moin capo,
so würde ich das wohl bei einer solchen Dateigrösse machen:
Delphi-Quellcode:
für die MD5-Funktionen kannst Du dies nehmen.
var
fIN : TextFile; fOUT : TextFile; sl : TStringList; sLine : string; sMD5 : string; begin sl := TStringList.Create; try sl.Sorted := true; AssignFile(fIN,'<Pfad der Quelldatei>'); AssignFile(fOUT,'<Pfad der Zieldatei>'); Reset(fIN); Rewrite(fOUT); try Readln(fIn,sLine); while not Eof(fIN) do begin sMD5 := MD5Print(MD5String(sLine)); if sl.IndexOf(sMD5) = -1 then begin sl.Add(sMD5); Writeln(fOUT); end; Readln(fIN,sLine); end; finally CloseFile(fOUT); CloseFile(fIN); end; finally FreeAndNil(sl); end; end; Sicher kostest es Zeit die MD5 zu berechnen, um einen doppelten String zu ermitteln, aber bei der Datenmenge könnte es schneller sein. Eine andere Variante:
Delphi-Quellcode:
var
fIN : TextFile; slOut : TStringList; sLine : string; begin slOut := TStringList.Create; try slOut.Capacity := 1000000; slOut.Sorted := True; slOut.CaseSensitive := False; slOut.Duplicates := dupIgnore; AssignFile(fIN,'<Pfad der Quelldatei>'); Reset(fIN); try Readln(fIn,sLine); while not Eof(fIN) do begin slOut.Add(sLine); Readln(fIN,sLine); end; finally CloseFile(fIN); end; slOut.SaveToFile('<Pfad der Zieldatei>'); finally FreeAndNil(slOut); end; end; |
Re: 80 MB Datei - doppelte Zeilen entfernen
hallo christian
dankeschön für deine beispiele. :-D |
Re: 80 MB Datei - doppelte Zeilen entfernen
Moin Christian,
du ignorierst in beiden Varianten die letzte Zeile der Eingabedatei. Das Ergebnis der ersten Variante ist sicher auch nicht das gewünschte. Korrektur der Variante 1:
Delphi-Quellcode:
Korrektur der Variante 2:
[...]
try // Readln(fIn,sLine); // entfernt while not Eof(fIN) do begin Readln(fIn,sLine); // neu sMD5 := MD5Print(MD5String(sLine)); if sl.IndexOf(sMD5) = -1 then begin sl.Add(sMD5); Writeln(fOUT, sLine); // korrigiert end; // Readln(fIN,sLine); // entfernt end; finally [...]
Delphi-Quellcode:
Gruß Hawkeye
[...]
try // Readln(fIn,sLine); // entfernt while not Eof(fIN) do begin Readln(fIn,sLine); // neu slOut.Add(sLine); // Readln(fIN,sLine); // entfernt end; finally [...] |
Re: 80 MB Datei - doppelte Zeilen entfernen
Zitat:
Du läßt uns hier rumrätzeln, weil Du Deine Frage so schwammig gestellt hast... Na was den nu? Sind die doppelten jetzt über die Datei verteilt oder liegen die hintereinander? Wenn es 80MB sind und es sich dabei um Adressen handelt sind das bei typischer Adressgröße ca. 500.000-700.000 Adressen...(Zeilen), richtig? Dann vielleicht sowas...
Delphi-Quellcode:
Frank :coder:
type
TSorter = Record CRC : longint; Zeile : longint; end; var Sort : array of TSorter; Count : integer; S : String; i : integer; begin assignfile(fd1,'Adressen.txt'); reset(fd1); Count := 0; Setlength(Sort,500000); while not(eof(fd1)) do begin readln(fd1,S); if length(Sort) > Count+1 then begin Sort.CRC := CRC4(S); // Oder auch den HD5 Sort.Zeile := Count; end else begin Setlength(Sort,Count + 10000); // Je größer die Zahl, desto schneller... end; inc(Count) end; Closefile(fd1); QSort(Sort,0,Count); // Gibt es von mir hier eine Kombo... // Den rest überlasse ich Dir... // Doppelte aus dem Array löschen... // Dann nur die Zeilen in die andere Dateikopieren, wenn Count in sort.Zeile end; PS.: Und wenn es dann noch nicht schnell genug ist... Zip die Adress-Datei zusammen und leg sie irgendwo hin... Denn das Antworten hier dauert jetzt schon länger als eine Konvertierung.. :-) |
Re: 80 MB Datei - doppelte Zeilen entfernen
Ich weiß jetzt nicht, was Franks QSort so macht, aber wenn die Reihenfolge der Elemente in der Liste geändert werden darf, würde ich auf jeden Fall Shellsort vorschlagen. Das sollte bei der Datenmenge das schnellste Verfahren sein.
Baue doch einfach mal ein paar Cardinals ein und ermittle den TickCount. Dann weißt du, an welcher Stelle du am Besten optimieren solltest. Edit: Noch was. Was machst du denn mit den Adressen? Falls du vorhast, sie anschließend in eine DB einzulesen, dann spar dir doch das Bearbeiten der Datei und mach die Logik lieber mit der DB. |
Re: 80 MB Datei - doppelte Zeilen entfernen
Zitat:
Zitat:
Frank :coder: |
Re: 80 MB Datei - doppelte Zeilen entfernen
Hallo und auch gleich ein SORRY.
Ja es sind Adressen. Ich dachte es ist egal was in den Zeilen steht wenn ich sage das diese doppelt oder mehrfach vorkommen. Wieder etwas gelernt. Danke an ALLE Gruss Capo |
Re: 80 MB Datei - doppelte Zeilen entfernen
Zitat:
Frank |
Re: 80 MB Datei - doppelte Zeilen entfernen
Hallo Mavarik
Danke für deine Nachfrage. Kann's nicht kompilieren und starten Bleibt hier hängen:
Delphi-Quellcode:
Sort.CRC := CRC4(S); // Oder auch den HD5
Zitat:
|
Re: 80 MB Datei - doppelte Zeilen entfernen
Ja klar...
Musst du halt eine CRC Funktion oder Deine HD5 Funktion einbauen... Frank |
Re: 80 MB Datei - doppelte Zeilen entfernen
Klar :-D
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:37 Uhr. |
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