StringList.SaveToFile: an bestehende Datei anhängen?
- photor
- Beiträge: 354
- Registriert: Mo 24. Jan 2011, 21:38
- OS, Lazarus, FPC: Arch Linux: L 2.2.4 FPC 3.2.2 (Gtk2)
- CPU-Target: 64Bit
StringList.SaveToFile: an bestehende Datei anhängen?
Hallo Forum,
Einfache Frage (und ich fürchte, ich kenne die Antwort):
Man kann ja eine StringList mit StringList.SaveToFile("Datei.txt") in eine Datei speichern. Die wird dabei leider überschrieben.
Kann man das verhindern und die den Inhalt der StringList an eine bestehende Datei anhängen? Durch einen Parameter, ein Flag oder ähnlich?
Der Huntergrund ist, dass in der StringList einige Minimum- und Maximum-Werte für die Durchläufe einer Rechnung gesammelt werden. Da das sehr viele Durchläufe (über lange Zeit) sein können, kommt es vor, dass so eine Rechnung abgebrochen werden muss, oder das auch schon mal von alleine tut. Wenn man die neu startet kann man sagen, ab welchem Durchlauf weiter gerechnet werden soll. Dabei wird leider die Datei mit dem Min- und Max-Werten überschrieben.
Der Work-around ist eigentlich klar: man liest die Datei vorher in die StringList mittels .LoadFromFile(), bevor man man neue Zeilen anhängt. Ist aber ein bisschen "durch die Brust ins Auge.
Gibt es eine einfache Möglichkeit - neben dem Würg-around? Und wenn "nein", warum eigentlich nicht?
Ciao,
Photor
Einfache Frage (und ich fürchte, ich kenne die Antwort):
Man kann ja eine StringList mit StringList.SaveToFile("Datei.txt") in eine Datei speichern. Die wird dabei leider überschrieben.
Kann man das verhindern und die den Inhalt der StringList an eine bestehende Datei anhängen? Durch einen Parameter, ein Flag oder ähnlich?
Der Huntergrund ist, dass in der StringList einige Minimum- und Maximum-Werte für die Durchläufe einer Rechnung gesammelt werden. Da das sehr viele Durchläufe (über lange Zeit) sein können, kommt es vor, dass so eine Rechnung abgebrochen werden muss, oder das auch schon mal von alleine tut. Wenn man die neu startet kann man sagen, ab welchem Durchlauf weiter gerechnet werden soll. Dabei wird leider die Datei mit dem Min- und Max-Werten überschrieben.
Der Work-around ist eigentlich klar: man liest die Datei vorher in die StringList mittels .LoadFromFile(), bevor man man neue Zeilen anhängt. Ist aber ein bisschen "durch die Brust ins Auge.
Gibt es eine einfache Möglichkeit - neben dem Würg-around? Und wenn "nein", warum eigentlich nicht?
Ciao,
Photor
Re: StringList.SaveToFile: an bestehende Datei anhängen?
Man könnte einen TFileStream zu Hülfe nehmen, wenn man zu wenig RAM hat für den Text.
Code: Alles auswählen
var
FStream: TFileStream;
SL:TStringList;
begin
FStream := TFileStream.Create('/home/theo/filename.txt', fmOpenWrite);
FStream.Seek(0, soEnd);
SL:=TStringList.Create;
SL.Text:='testen';
FStream.Write(SL.Text[1],Length(SL.Text));
SL.free;
FStream.free;
end;
- Jorg3000
- Lazarusforum e. V.
- Beiträge: 109
- Registriert: So 10. Okt 2021, 10:24
- OS, Lazarus, FPC: Win64
- Wohnort: NRW
Re: StringList.SaveToFile: an bestehende Datei anhängen?
Das Anhängen an die Datei ist eine schöne Lösung von Theo.
Der zweimalige Aufruf von SL.Text ist jedoch unschön, wenn es sich um eine Liste mit vielen Strings handelt.
Der zweimalige Aufruf von SL.Text ist jedoch unschön, wenn es sich um eine Liste mit vielen Strings handelt.
Code: Alles auswählen
var
FStream: TFileStream;
SL:TStringList;
s: String;
begin
// hier bestehende SL vorausgesetzt
s:=SL.Text;
if s<>'' then
try
FStream :=nil; // wegen Finally falls schon TFileStream.Create() fehlschlägt
FStream := TFileStream.Create('/home/theo/filename.txt', fmOpenWrite);
FStream.Seek(0, soEnd);
FStream.Write(s[1],Length(s));
finally
FStream.free;
end;
end;
-
- Lazarusforum e. V.
- Beiträge: 3123
- Registriert: Di 22. Jul 2008, 19:27
- OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
- CPU-Target: 32bit x86 armhf
- Wohnort: Köln
- Kontaktdaten:
Re: StringList.SaveToFile: an bestehende Datei anhängen?
Wenn die zu schreibenden Daten ohnehin in einer StringList vorhanden sind, ist der Aufruf von .Text komplett überflüssig. Das braucht gerade bei großen Stringlisten zu viel Zeit und Speicher. Da kann man die einzelnen Strings doch direkt in die Datei schreiben.
Man kombiniere einfach theo's Aufruf FStream.Seek(0, soEnd) um an das Ende eines Streams zu springen mit TStrings.SaveToFile miteinander:
Man kombiniere einfach theo's Aufruf FStream.Seek(0, soEnd) um an das Ende eines Streams zu springen mit TStrings.SaveToFile miteinander:
Code: Alles auswählen
Procedure AppendStringsToFile(aStrings: TStrings; const FileName: string);
Var TheStream : TFileStream;
begin
TheStream:=TFileStream.Create(FileName,fmOpenWrite);
try
TheStream.Seek(0, soEnd);
aStrings.SaveToStream(TheStream);
finally
TheStream.Free;
end;
end;
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein
- photor
- Beiträge: 354
- Registriert: Mo 24. Jan 2011, 21:38
- OS, Lazarus, FPC: Arch Linux: L 2.2.4 FPC 3.2.2 (Gtk2)
- CPU-Target: 64Bit
Re: StringList.SaveToFile: an bestehende Datei anhängen?
Hallo Forum,
Zunächst mal "Danke" für den ganzen Input.
Wenn ich das so richtig sehe, gibt es
Ciao,
Photor
Zunächst mal "Danke" für den ganzen Input.
Die Idee mit einem Stream hatte ich auch schon - ist aber (auch) nicht ganz einfach in den bisherigen Programmablauf zu integrieren (das Programm ist ein über Jahrzehnte gewachsenes - und dabei von diversen Leuten aufgezogenes; will heißen; die Struktur ist nicht immer gut durchdacht). Aber ich schaue mir das Ganze mal daraufhin an.
Pro Durchlauf wird eine Zeile eingetragen. Anzahl der Durchläufe: 100 ... 900. Das, denke ich, macht keine großen Probleme im Speicher (die Maschine hat jedenfalls genug davon - die macht auch FE-Berechnungen).Socke hat geschrieben: ↑Fr 13. Jan 2023, 19:45Wenn die zu schreibenden Daten ohnehin in einer StringList vorhanden sind, ist der Aufruf von .Text komplett überflüssig. Das braucht gerade bei großen Stringlisten zu viel Zeit und Speicher. Da kann man die einzelnen Strings doch direkt in die Datei schreiben.
War in etwa meine spontane Idee, als mein Kollege mit dem Bug/Wunsch kam, dass bitte alle(!) Einträge im File enthalten sind - auch nach Restart. Beim Blick in den Programm-Code war dann die Idee, neue Einträge mittels SaveToFile anzuhängen - wäre das einfachste.
Wenn ich das so richtig sehe, gibt es
- wohl keine Option gibt, mit der StringList.SaveToFile unmittelbar zum Anhängen an ein bestehnedes File zu bewegen ist
- entweder mit StringList.LoadFromFile das alte File in StringList geladen und die weiteren Einträge anhängen und am Ende wieder ganz normal mit StringList.SaveToFile rausschreiben - oder
- die Lösung mit FileStream.Seek an das Ende des (eventuell) vorhandenen Files gehen und dort die weiteren Einträge anhängen FileStream.Write oder mit StringList.SaveToFile speichern
Ciao,
Photor
Re: StringList.SaveToFile: an bestehende Datei anhängen?
Eigentlich ein idealer Fall für einen Class Helper.
Code: Alles auswählen
{$mode objfpc}{$H+}
...
type
{ TAppendStringList }
TAppendStringList = class helper for TStringList
procedure AppendToFile(const FileName: string);
end;
...
implementation
{ TAppendStringList }
procedure TAppendStringList.AppendToFile(const FileName: string);
var
TheStream: TFileStream;
Mode: word;
begin
if FileExists(FileName) then
Mode := fmOpenWrite
else
Mode := fmCreate;
TheStream := TFileStream.Create(FileName, Mode);
try
TheStream.Seek(0, soEnd);
Self.SaveToStream(TheStream);
finally
TheStream.Free;
end;
end;
...
procedure TForm1.Button1Click(Sender: TObject);
var
SL: TStringList;
begin
SL := TStringList.Create;
SL.Text := 'Test';
Sl.AppendToFile('testeappend.txt');
SL.Free;
end;
- photor
- Beiträge: 354
- Registriert: Mo 24. Jan 2011, 21:38
- OS, Lazarus, FPC: Arch Linux: L 2.2.4 FPC 3.2.2 (Gtk2)
- CPU-Target: 64Bit
Re: StringList.SaveToFile: an bestehende Datei anhängen?
Moin,
oh. Das ist ein neuer Aspekt - nicht nur hier, sondern auch für mich!
Das muss ich mir mal in Ruhe ansehen.
Merci,
Photor
oh. Das ist ein neuer Aspekt - nicht nur hier, sondern auch für mich!
Das muss ich mir mal in Ruhe ansehen.
Merci,
Photor
Re: StringList.SaveToFile: an bestehende Datei anhängen?
Schwierig ist es nicht zu verstehen.
Du erweiterst so die Funktionalität der Stringlist, ohne dafür eine Klasse ableiten zu müssen.
Falls du die Erweiterung in mehreren Units brauchst, dann lege den Class Helper z.B. in eine Unit mit Hilfsfunktionen, die du überall einbinden kannst.
Eigentlich genau was du wolltest.
Re: StringList.SaveToFile: an bestehende Datei anhängen?
Ich versuche diese Dinger weitgehend zu vermeiden, vor allem weil ich nicht up-to-date bin. Vor einiger Zeit hat mir jemand einmal gesagt, dass es zu einem Typ nur einen Helper geben kann. Das heißt womöglich, dass ich einen existierenden Helper deaktiviere, wenn ich selbst einen Helper schreibe. Wenn also irgendwo in der FCL, RTL, LCL ein Helper für TStringList implementiert worden ist, und ich mir dafür einen eigenen Helper schreibe, gehen vielleicht Teile der FCL/RTL/LCL nicht mehr? Ist das so richtig? Oder kann ich nur den ursprünglichen Helper, den ich überschrieben habe, nicht mehr verwenden?
Ohne einen Helper, und ohne diese Unsicherheit, tut's eine einfache Prozedur auch, ist natürlich nicht so schick:
Code: Alles auswählen
procedure AppendStringsToFile(AStrings: TStrings; AFileName: String);
var
stream: TFileStream;
Mode: word;
begin
if FileExists(AFileName) then
Mode := fmOpenWrite
else
Mode := fmCreate;
stream := TFileStream.Create(AFileName, Mode);
try
stream.Seek(0, soEnd);
AStrings.SaveToStream(stream);
finally
stream.Free;
end;
end;
-
- Lazarusforum e. V.
- Beiträge: 3123
- Registriert: Di 22. Jul 2008, 19:27
- OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
- CPU-Target: 32bit x86 armhf
- Wohnort: Köln
- Kontaktdaten:
Re: StringList.SaveToFile: an bestehende Datei anhängen?
Dein Code kann immer nur einen Helper pro Typ nutzen. Wenn die RTL/FCL einen Helper für TStrings oder TStringList definiert, kannst du deinen Helper davon ableiten (wie bei ganz normalen Klassen) und hast dann auch dessen Methoden.wp_xyz hat geschrieben: ↑Sa 14. Jan 2023, 12:35Vor einiger Zeit hat mir jemand einmal gesagt, dass es zu einem Typ nur einen Helper geben kann. Das heißt womöglich, dass ich einen existierenden Helper deaktiviere, wenn ich selbst einen Helper schreibe. Wenn also irgendwo in der FCL, RTL, LCL ein Helper für TStringList implementiert worden ist, und ich mir dafür einen eigenen Helper schreibe, gehen vielleicht Teile der FCL/RTL/LCL nicht mehr? Ist das so richtig? Oder kann ich nur den ursprünglichen Helper, den ich überschrieben habe, nicht mehr verwenden?
Wenn du das nicht machst, überdeckst du nur den Standard-Helper und nur die Methoden deines eigenen Helpers können aufgerufen werden.
Da die RTL/FCL/LCL deine Units nicht kennt, wird sie immer mit den dort definierten Helpern arbeiten können. Das ist genau so wie bei allen anderen Funktionen/Methoden/Klassen und so weiter - es wird nur das beachtet, was im Uses-Abschnitt steht.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein
Re: StringList.SaveToFile: an bestehende Datei anhängen?
OK, verstanden. Anders ausgedrückt: Es kann sehr wohl verschiedene Helper pro Typ geben, sofern diese in unterschiedlichen Units stehen. Und es wird immer derjenige Helper verwendet, dessen Unit in der "uses"-Zeile der ihn aufrufenden Unit genannt ist. Oder?Socke hat geschrieben: ↑Sa 14. Jan 2023, 12:56Dein Code kann immer nur einen Helper pro Typ nutzen. Wenn die RTL/FCL einen Helper für TStrings oder TStringList definiert, kannst du deinen Helper davon ableiten (wie bei ganz normalen Klassen) und hast dann auch dessen Methoden.wp_xyz hat geschrieben: ↑Sa 14. Jan 2023, 12:35Vor einiger Zeit hat mir jemand einmal gesagt, dass es zu einem Typ nur einen Helper geben kann. Das heißt womöglich, dass ich einen existierenden Helper deaktiviere, wenn ich selbst einen Helper schreibe. Wenn also irgendwo in der FCL, RTL, LCL ein Helper für TStringList implementiert worden ist, und ich mir dafür einen eigenen Helper schreibe, gehen vielleicht Teile der FCL/RTL/LCL nicht mehr? Ist das so richtig? Oder kann ich nur den ursprünglichen Helper, den ich überschrieben habe, nicht mehr verwenden?
Wenn du das nicht machst, überdeckst du nur den Standard-Helper und nur die Methoden deines eigenen Helpers können aufgerufen werden.
Da die RTL/FCL/LCL deine Units nicht kennt, wird sie immer mit den dort definierten Helpern arbeiten können. Das ist genau so wie bei allen anderen Funktionen/Methoden/Klassen und so weiter - es wird nur das beachtet, was im Uses-Abschnitt steht.
Re: StringList.SaveToFile: an bestehende Datei anhängen?
Naja, wenn du die anderen Helper (Ggf.) nicht benötigst, sehe ich da keine Gefahr.
Die RTL/FCL/LCL wirst du damit nicht aus der Ruhe bringen.
Ja, deshalb hatte ich auch geschrieben: "Falls du die Erweiterung in mehreren Units brauchst, dann lege den Class Helper z.B. in eine Unit mit Hilfsfunktionen, die du überall einbinden kannst."wp_xyz hat geschrieben: ↑Sa 14. Jan 2023, 14:25OK, verstanden. Anders ausgedrückt: Es kann sehr wohl verschiedene Helper pro Typ geben, sofern diese in unterschiedlichen Units stehen. Und es wird immer derjenige Helper verwendet, dessen Unit in der "uses"-Zeile der ihn aufrufenden Unit genannt ist. Oder?
Ich finde das Schick. Bei nicht-visuellen Komponenten ginge ein abgeleitete Klasse nat. auch recht einfach.
Trotzdem müsste er so Deklarationen ändern, was er mit dem Helper nicht muss.