letzte Zeilen einer riesengroßen Textdatei in ein Memofeld
- willi4willi
- Lazarusforum e. V.
- Beiträge: 176
- Registriert: Sa 1. Nov 2008, 18:06
- OS, Lazarus, FPC: Lazarus 3.8 FPC 3.2.2 x86_64-win64-win32/win64 x86_64-linux-gtk2
- CPU-Target: i386, win64, arm
letzte Zeilen einer riesengroßen Textdatei in ein Memofeld
Hallo allerseits,
folgendes Problem:
Ein Logfile ist riesengroß geworden (ca. 20 MB). Die letzten 10 Zeilen sollen periodisch (z.B. mittels Timer) in einem Memo-Feld dargestellt werden.
Mit AssignFile(TextFile,Dateiname) und Seek(TextFile,Position) kann ich nicht in der Datei nach hinten springen.
Und mit TStringList.LoadFromFile(Dateiname) wird die gesamte Datei eingelesen. Bei der Dateigröße ist das der Horror.
Hat jemand eine Idee, wie ich zur zehntletzten Zeile springen kann und ab dort bis zum Dateiende die letzten zehn Zeilen einlesen kann, ohne durch die Danze Datei zu müssen?
Viele Grüße
Willi4Willi
folgendes Problem:
Ein Logfile ist riesengroß geworden (ca. 20 MB). Die letzten 10 Zeilen sollen periodisch (z.B. mittels Timer) in einem Memo-Feld dargestellt werden.
Mit AssignFile(TextFile,Dateiname) und Seek(TextFile,Position) kann ich nicht in der Datei nach hinten springen.
Und mit TStringList.LoadFromFile(Dateiname) wird die gesamte Datei eingelesen. Bei der Dateigröße ist das der Horror.
Hat jemand eine Idee, wie ich zur zehntletzten Zeile springen kann und ab dort bis zum Dateiende die letzten zehn Zeilen einlesen kann, ohne durch die Danze Datei zu müssen?
Viele Grüße
Willi4Willi
Viele Grüße
Willi4Willi
------------
-
Euklid
- Lazarusforum e. V.
- Beiträge: 2808
- Registriert: Fr 22. Sep 2006, 10:38
- OS, Lazarus, FPC: Lazarus v2.0.10, FPC 3.2.0
- Wohnort: Hessen
- Kontaktdaten:
Re: letzte Zeilen einer riesengroßen Textdatei in ein Memofeld
Bei Textdateien hat man denke ich keine andere Wahl, als die Datei vollständig einzulesen.
(wobei READLN schneller sein könnte als stringlist)
http://www.lazarusforum.de/portal.php?c ... ery=readln" onclick="window.open(this.href);return false;
(wobei READLN schneller sein könnte als stringlist)
http://www.lazarusforum.de/portal.php?c ... ery=readln" onclick="window.open(this.href);return false;
-
Linkat
- Lazarusforum e. V.
- Beiträge: 582
- Registriert: So 10. Sep 2006, 23:24
- OS, Lazarus, FPC: Linux Mint 22.1; Lazarus 4.2 FPC 3.2.2; RaspiOS
- CPU-Target: AMD 64, ARM 64
- Wohnort: nr Stuttgart
Re: letzte Zeilen einer riesengroßen Textdatei in ein Memofeld
Hallo,
ich würde dieLogdatei in eine Stringliste einlesen und mit:
die 10 Zeilen darstellen. Ob readln schneller ist, kann ich nicht sagen, aber Ich arbeite auch sehr häufig mit großen Logfiles. Die Geschwindigkeit war noch nie ein Problem.
Gruß, Linkat
ich würde dieLogdatei in eine Stringliste einlesen und mit:
Code: Alles auswählen
for i:=stringliste.count-11 to stringlist.count-1 do begin
....
end;Gruß, Linkat
Linux Mint 22.1; Lazarus 4.2 FPC 3.2.2; RaspiOS
Re: letzte Zeilen einer riesengroßen Textdatei in ein Memofeld
Wenn man abschätzen kann, wie gross eine Zeile werden kann, könnte man evtl. auch "genügend" Bytes vom Ende mittels TFileStream einlesen, und dann in einer StringList weiterverarbeiten.
soFromEnd:
http://www.freepascal.org/docs-html/rtl ... .seek.html" onclick="window.open(this.href);return false;
Ist nur so eine Idee, die Performance kann ich nicht einschätzen.
soFromEnd:
http://www.freepascal.org/docs-html/rtl ... .seek.html" onclick="window.open(this.href);return false;
Ist nur so eine Idee, die Performance kann ich nicht einschätzen.
-
Scotty
- Beiträge: 768
- Registriert: Mo 4. Mai 2009, 13:24
- OS, Lazarus, FPC: Arch Linux, Lazarus 1.3 r44426M FPC 2.6.4
- CPU-Target: x86_64-linux-qt/gtk2
- Kontaktdaten:
Re: letzte Zeilen einer riesengroßen Textdatei in ein Memofeld
Wie wäre es mit einem Aufruf von tail?
- willi4willi
- Lazarusforum e. V.
- Beiträge: 176
- Registriert: Sa 1. Nov 2008, 18:06
- OS, Lazarus, FPC: Lazarus 3.8 FPC 3.2.2 x86_64-win64-win32/win64 x86_64-linux-gtk2
- CPU-Target: i386, win64, arm
Re: letzte Zeilen einer riesengroßen Textdatei in ein Memofeld
Danke für die Tipps!
Das Einlesen in eine StringList ist zu langsam (Dateigröße 24 MB und über 68000 Zeilen).
Mit Readln stelle ich nun die Größe der Datei fest, wandere dann bis zu 10 Zeilen vor das Ende und lese dann die restlichen 10 Zeilen ein.
Das ist zwar ziemlich umständlich, aber scheinbar die beste Lösung. Wenn ich den Timer auf 1000 ms einstelle dann ist das auf meinem Rechner noch akzeptabel.
Klar, das Unix-Kommando tail oder less machen genau das, wass ich will, aber unter Windows?
Danke allen und ein schönes Wochenende!
Das Einlesen in eine StringList ist zu langsam (Dateigröße 24 MB und über 68000 Zeilen).
Mit Readln stelle ich nun die Größe der Datei fest, wandere dann bis zu 10 Zeilen vor das Ende und lese dann die restlichen 10 Zeilen ein.
Code: Alles auswählen
procedure TForm1.LadeMitReadln;
var LogFile : TextFile;
S : String;
Lauf, Zeilen : longint;
Begin
if FileExists(OpenDialog1.FileName) then
begin
AssignFile(LogFile,OpenDialog1.FileName);
FileMode := fmOpenRead;
Reset(LogFile);
memo1.Lines.BeginUpdate;
memo1.Lines.Clear;
Zeilen:=0;
while not eof(LogFile) do
begin
Readln(LogFile);
inc(Zeilen);
end;
CloseFile(LogFile);
reset(LogFile);
for Lauf:=0 to Zeilen-10 do Readln(LogFile);
while not eof(LogFile) do
begin
Readln(LogFile,s);
Memo1.Lines.Add(s);
end;
Memo1.Lines.EndUpdate;
CloseFile(LogFile);
end;
end;Das ist zwar ziemlich umständlich, aber scheinbar die beste Lösung. Wenn ich den Timer auf 1000 ms einstelle dann ist das auf meinem Rechner noch akzeptabel.
Klar, das Unix-Kommando tail oder less machen genau das, wass ich will, aber unter Windows?
Danke allen und ein schönes Wochenende!
Viele Grüße
Willi4Willi
------------
-
Euklid
- Lazarusforum e. V.
- Beiträge: 2808
- Registriert: Fr 22. Sep 2006, 10:38
- OS, Lazarus, FPC: Lazarus v2.0.10, FPC 3.2.0
- Wohnort: Hessen
- Kontaktdaten:
Re: letzte Zeilen einer riesengroßen Textdatei in ein Memofeld
Willi4Willi: Noch deutlich schneller als Readln dürfte Blockread sein. Damit liesst Du richtig grosse Blöcke auf einen Schlag ein und kannst dann den letzten Block untersuchen. Das dürfte aber noch aufwändiger sein...^^
http://www.lazarusforum.de/portal.php?c ... =blockread" onclick="window.open(this.href);return false;
http://www.lazarusforum.de/portal.php?c ... =blockread" onclick="window.open(this.href);return false;
- m.fuchs
- Lazarusforum e. V.
- Beiträge: 2897
- Registriert: Fr 22. Sep 2006, 19:32
- OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
- CPU-Target: x86, x64, arm
- Wohnort: Berlin
- Kontaktdaten:
Re: letzte Zeilen einer riesengroßen Textdatei in ein Memofeld
Es gibt auch Tail für Windows, zum Beispiel: http://tailforwin32.sourceforge.net/. Hat auch gleich noch nette Features wie Highlighting von bestimmten Begriffen und ähnliches.willi4willi hat geschrieben:Klar, das Unix-Kommando tail oder less machen genau das, wass ich will, aber unter Windows?
0118999881999119725-3
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de
- corpsman
- Lazarusforum e. V.
- Beiträge: 1781
- Registriert: Sa 28. Feb 2009, 08:54
- OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
- CPU-Target: 64Bit
- Wohnort: Stuttgart
- Kontaktdaten:
Re: letzte Zeilen einer riesengroßen Textdatei in ein Memofeld
Ohh, wenn ich das sehe, 2-Pass wo es einer tun würde ...
wie wärs mit sowas :Code: Alles auswählen
procedure TForm1.LadeMitReadln; var LogFile : TextFile; S : String; Lauf, Zeilen : longint; Begin if FileExists(OpenDialog1.FileName) then begin AssignFile(LogFile,OpenDialog1.FileName); FileMode := fmOpenRead; Reset(LogFile); memo1.Lines.BeginUpdate; memo1.Lines.Clear; Zeilen:=0; while not eof(LogFile) do begin Readln(LogFile); inc(Zeilen); end; CloseFile(LogFile); reset(LogFile); for Lauf:=0 to Zeilen-10 do Readln(LogFile); while not eof(LogFile) do begin Readln(LogFile,s); Memo1.Lines.Add(s); end; Memo1.Lines.EndUpdate; CloseFile(LogFile); end; end;
Code: Alles auswählen
procedure TForm1.LadeMitReadln;
var
LogFile: TextFile;
buffer: array[0..9] of string;
buffer_ptr: Integer;
i: integer;
begin
if FileExists(OpenDialog1.FileName) then begin
AssignFile(LogFile, OpenDialog1.FileName);
Reset(LogFile);
buffer_ptr := 0;
while not eof(LogFile) do begin
buffer[buffer_ptr] := Readln(LogFile);
buffer_ptr := (buffer_ptr + 1) mod 10;
end;
CloseFile(LogFile);
memo1.Lines.BeginUpdate;
memo1.Lines.Clear;
for i := 0 to 9 do begin
Memo1.Lines.Add(buffer[(buffer_ptr - i + 10) mod 10]);
end;
Memo1.Lines.EndUpdate;
end;
end;--
Just try it
Just try it
Re: letzte Zeilen einer riesengroßen Textdatei in ein Memofeld
Willst du meinen Vorschlag nicht wenigstens testen?
Das geht doch recht schnell:
Das kann man noch sicherer und evtl. besser machen, aber müsste klappen.
Das geht doch recht schnell:
Code: Alles auswählen
function ReadTail(FileName:AnsiString; Lines:integer=10; MaxLineSize:integer=80):AnsiString;
var fs:TFileStream;
sl:TStringList;
Bts:integer;
Buf:AnsiString;
begin
fs:=TFileStream.Create(FileName,fmOpenRead);
bts:=Lines*MaxLineSize;
fs.Seek(-bts,soFromEnd);
SetLength(Buf,bts);
fs.Read(Buf[1],bts);
sl:=TStringList.Create;
sl.Text:=Buf;
sl.BeginUpdate;
Repeat
sl.Delete(0);
until sl.Count<Lines+1;
sl.EndUpdate;
Result:=sl.text;
sl.free;
fs.free;
end;- willi4willi
- Lazarusforum e. V.
- Beiträge: 176
- Registriert: Sa 1. Nov 2008, 18:06
- OS, Lazarus, FPC: Lazarus 3.8 FPC 3.2.2 x86_64-win64-win32/win64 x86_64-linux-gtk2
- CPU-Target: i386, win64, arm
Re: letzte Zeilen einer riesengroßen Textdatei in ein Memofeld
Hallo,
Vielen Dank für die rege Teilnahme an dieser Problemstellung.
Die Idee von corpsmann ist schon gar nicht mal so schlecht. Ich hatte mit meiner Lösung ca. 610 ms benötigt. Durch den einen Durchlauf komme ich auf ca. 330 ms.
So funktionierte es:
Aber die Lösung von Teo ist total genial!
Besonders von deren Geschwindigkeit bin ich absolut begeistert. Genau der Sprung bis fast ans Ende der Datei war der springende Punkt.
Die Geschwindigkeit mit dieser Funktion lag unter 1 ms. Super!!
Alle anderen Ideen vergessen wir mal. Das ist die Lösung.
Vielen Dank an alle, die mitgedacht haben.
Willi4willi
Vielen Dank für die rege Teilnahme an dieser Problemstellung.
Die Idee von corpsmann ist schon gar nicht mal so schlecht. Ich hatte mit meiner Lösung ca. 610 ms benötigt. Durch den einen Durchlauf komme ich auf ca. 330 ms.
So funktionierte es:
Code: Alles auswählen
procedure TForm1.LadeMitReadln;
var
LogFile: TextFile;
buffer: array[0..9] of string;
buffer_ptr: Integer;
i: integer;
begin
if FileExists(OpenDialog1.FileName) then begin
AssignFile(LogFile, OpenDialog1.FileName);
Reset(LogFile);
buffer_ptr := 0;
while not eof(LogFile) do begin
Readln(LogFile,buffer[buffer_ptr]);
buffer_ptr := (buffer_ptr + 1) mod 10;
end;
CloseFile(LogFile);
memo1.Lines.BeginUpdate;
memo1.Lines.Clear;
for i := 0 to 9 do
begin
Memo1.Lines.Add(buffer[((buffer_ptr + i) mod 10)]);
end;
Memo1.Lines.EndUpdate;
end;
end;Besonders von deren Geschwindigkeit bin ich absolut begeistert. Genau der Sprung bis fast ans Ende der Datei war der springende Punkt.
Die Geschwindigkeit mit dieser Funktion lag unter 1 ms. Super!!
Alle anderen Ideen vergessen wir mal. Das ist die Lösung.
Vielen Dank an alle, die mitgedacht haben.
Willi4willi
Viele Grüße
Willi4Willi
------------
-
mschnell
- Beiträge: 3444
- Registriert: Mo 11. Sep 2006, 10:24
- OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
- CPU-Target: X32 / X64 / ARMv5
- Wohnort: Krefeld
Re: letzte Zeilen einer riesengroßen Textdatei in ein Memofeld
SetLength(Buf,bts);
...
sl.Text:=Buf;
Damit belegst Du zweimal das Memory für die komplette "riesengroße Textdate" ?!?!?!?!?!
Dann schon besser:
sl.LoadFromStream(fs);
-Michael
...
sl.Text:=Buf;
Damit belegst Du zweimal das Memory für die komplette "riesengroße Textdate" ?!?!?!?!?!
Dann schon besser:
sl.LoadFromStream(fs);
-Michael
-
mschnell
- Beiträge: 3444
- Registriert: Mo 11. Sep 2006, 10:24
- OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
- CPU-Target: X32 / X64 / ARMv5
- Wohnort: Krefeld
Re: letzte Zeilen einer riesengroßen Textdatei in ein Memofeld
Dann war die Datei wohl doch nicht so riesigwilli4willi hat geschrieben:Die Geschwindigkeit mit dieser Funktion lag unter 1 ms. Super!!
-Michael
- willi4willi
- Lazarusforum e. V.
- Beiträge: 176
- Registriert: Sa 1. Nov 2008, 18:06
- OS, Lazarus, FPC: Lazarus 3.8 FPC 3.2.2 x86_64-win64-win32/win64 x86_64-linux-gtk2
- CPU-Target: i386, win64, arm
Re: letzte Zeilen einer riesengroßen Textdatei in ein Memofeld
Hallo Michael,
vielleicht habe ich einen Denkfehler, aber wenn ich mit
sl.LoadFromStream(fs);
arbeite, wird dann nicht die ganze Datei eingelesen? Bei der Lösung von Theo sind es nur die letzten 10 Zeilen.
Geht das sl.LoadFromStream(fs) schneller als sl.LoadFromFile()? Dafür brauchte mein Programm 5400 ms.
Die Text-Datei hat 25.806.431 Byte. Nö, das ist nicht groß - verglichen mit einem FullHD-Video.
Viele Grüße
Willi4Willi
vielleicht habe ich einen Denkfehler, aber wenn ich mit
sl.LoadFromStream(fs);
arbeite, wird dann nicht die ganze Datei eingelesen? Bei der Lösung von Theo sind es nur die letzten 10 Zeilen.
Geht das sl.LoadFromStream(fs) schneller als sl.LoadFromFile()? Dafür brauchte mein Programm 5400 ms.
Die Text-Datei hat 25.806.431 Byte. Nö, das ist nicht groß - verglichen mit einem FullHD-Video.
Viele Grüße
Willi4Willi
Viele Grüße
Willi4Willi
------------
Re: letzte Zeilen einer riesengroßen Textdatei in ein Memofeld
???? Kopfschüttel.mschnell hat geschrieben:SetLength(Buf,bts);
...
sl.Text:=Buf;
Damit belegst Du zweimal das Memory für die komplette "riesengroße Textdate" ?!?!?!?!?!
-Michael