How can I use TFileStream to truncate the existing file before overwriting it? - lazarus

I am using the code below to write to an existing file, but the contents get appended. What TFileStream options are necessary to empty the file and overwrite it?
procedure TUtilitiesForm.btnSaveClick(Sender: TObject);
var fs: TFileStream;
begin
fs := TFileStream.Create(FileNameEdit1.Text, fmOpenWrite);
fs.Seek(0,fsFromEnd);
mmoDDL.Lines.SaveToStream(fs);
fs.Free;
end;

Using fsFromEnd you append data beyond the end of an existing file, on the other hand fsFromBeginning starts from the beginning but won't truncate the file.
Change from fmOpenWrite to fmCreate
procedure TUtilitiesForm.btnSaveClick(Sender: TObject);
var fs: TFileStream;
begin
fs := TFileStream.Create(FileNameEdit1.Text, fmCreate);
try
mmoDDL.Lines.SaveToStream(fs);
finally
FreeAndNil(fs);
end;
end;

Related

"" is an invalid integer lazarus

I have no idea how to fix it
procedure TForm1.Button1Click(Sender: TObject);
var conf, adult: Integer;
pr:real;
begin
adult:=StrToInt(Edit2.text);
conf:=StrToInt(Edit3.text);
pr:=StrToFloat(Edit4.text);
If Peak1.Checked then
pr:=(adult*8.95)+(conf*6.45)
else
pr:=(adult*7.45)+(conf*5.95);
Edit4.text:='£'+(FloatToStr(pr));
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
edit2.clear;
edit3.clear;
edit4.clear;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
close
end;
I tried to change from StrToInt to FloatToString, I have no idea how to fix it
The error "" is an invalid integer means you are trying to convert an empty string to a number which is impossible and hence the exception.
If you are not sure that the strings actually contain correctly written integers/floats, then use the TryStrToInt and TryStrToFloat functions. These functions do not throw exceptions and instead return a boolean value indicating whether the conversion succeeded — use the results to detect problems with user input.

Using Inno Setup scripting to insert lines into a text file?

Objective is to insert multiple lines (once) at beginning of text document.
But I have been having problems with the approaches I found. I've attempted to adjust them but it incorporates side-effect issues.
Two problems:
Appends end of file instead of inserting into line locations.
In its present design, it appends the file 3 times.
In reference to the other scripts I found both lines incorporating Result := resulted in unknown identifier.
References:
How to use Inno Setup scripting to append to a text file?
https://www.codeproject.com/Questions/477984/createplusandpluswriteplusbatchplusfileplusinplusi
[Code]
procedure CurStepChanged(CurStep: TSetupStep);
var
ErrorCode: Integer;
FileName: string;
lines : TArrayOfString;
begin
fileName := ExpandConstant('{userappdata}\xy');
fileName := AddBackslash(FileName) + 'zlt.net';
SetArrayLength(lines, 6);
lines[0] := 'A';
lines[1] := 'B';
lines[2] := 'C';
lines[3] := 'D';
lines[4] := 'E';
lines[5] := 'F';
SaveStringsToFile(filename,lines,true);
end;
There's no way to insert lines into file. You have to recreate whole file.
CurStepChanged is triggered for every step of the installation. You will want to insert the lines in one of the steps only (likely ssInstall or ssPostInstall)
procedure CurStepChanged(CurStep: TSetupStep);
var
Lines: TStringList;
begin
if CurStep = ssPostInstall then
begin
Lines := TStringList.Create;
try
Lines.LoadFromFile(FileName);
Lines.Insert(0, 'A');
Lines.Insert(1, 'B');
Lines.Insert(2, 'C');
Lines.Insert(3, 'D');
Lines.Insert(4, 'E');
Lines.Insert(5, 'F');
Lines.SaveToFile(FileName);
finally
Lines.Free;
end;
end;
end;
The code loads whole file to memory. That can be a problem if the file is too large. But that should not be a problem for files smaller than tens of MBs. Also repeatedly calling Insert is not efficient. But for small files and few lines, this should not be a problem either.

Edit File on Click of a button in Lazarus

Like I posted in a previous thread I want to create a little program which edits one line in a .ini file. Now I have implemented a button but don't further. I basically want to implement the following scenario:
1) Click Button
2) Because of button click, program opens .txt/.ini file (in background) the file is located in the same folder
3) One word in text file is changed with new word
4) file gets saved
5) message pops up
procedure TLauncher.ButtonClick(Sender: TObject);
var
begin
ShowMessage('.Ini-File was edited')
end;
That's simple to do, if you split what you want to do into procedures that only
do one thing each.
Assume your form has a string variable IniFileName which you initialize however
you want, e.g. using a TOpenDialog. Then you can have
procedure TForm1.LoadIni;
begin
Memo1.Lines.LoadfromFile(IniFileName);
end;
procedure TForm1.SaveIni;
begin
Memo1.Lines.SaveToFile(IniFileName);
end;
procedure TForm1.Button1Click;
begin
if OpenDialog1.Execute then begin
IniFileName := OpenDialog1.FileName;
LoadIni;
end;
end;
procedure TForm1.Button2Click;
begin
SaveIni;
ShowMessage(IniFileName + ' saved to disk');
end;

Writing datas to memobox from .txt file using Lazarus freepascal?

I've got a project at schools which requires to write datas from a .txt file to a "memobox" in Lazarus freepascal.
There are datas in order like this.
Budapest tomato 23
Dublin tv 45
Rosslare projector 43
etc.
I have to read these datas from a .txt file and then write them into a memobox in Lazarus freepascal.
If I am not mistaken I have already copyed the datas from the .txt file but I have no idea how to write them.
I've already written this code:
type
cityname:integer;
product:string;
quantity:integer;
var
Form1: TForm1;
ceg:array[1..5] of rektip;
db:integer;
implementation
procedure TForm1.Button1Click(Sender: TObject);
var f:textfile; i:integer; a:char;
begin
assignfile(f,'termek.txt');
reset(f);
readln(f,db);
While not eof(f) do
begin
readln(f,ceg[i].varosnev,a,ceg[i].termek,a,ceg[i].darabszam);
end;
db:=1;
closefile(f);
end;
procedure TForm1.Button2Click(Sender: TObject);
var i:integer;
begin
For i:=1 to db do
Memo1.lines.add(ceg[i].varosnev,ceg[i].termek,IntToStr(ceg[i].darabszam));
end;
end;
I would like to know how to fix it.
The code you posted is incomplete, so I assume:
type
rektip = record
varosnev: string;
termek: string;
darabszam: Integer;
end;
There is a lot wrong with your approach:
readln(f,db);
While not eof(f) do
begin
readln(f,ceg[i].varosnev,a,ceg[i].termek,a,ceg[i].darabszam);
end;
db:=1;
closefile(f);
end;
You are not initializing nor updating i, so you are reading all data into the same record, and you don't even know which one (i could be 100 and you'd be writing the data to somewhere unknown -- there is no ceg[100]). That results in undefined behaviour (and that can be a crash too).
Do something like:
var
ceg: array of rektip;
...
begin
AssignFile(f, 'termek.txt');
Reset(f);
Readln(f, db);
if db = 0 then
Exit;
SetLength(ceg, db);
i := 0;
while not eof(f) do
begin
Readln(f, ceg[i].varosnev, ceg[i].termek, ceg[i].darabszam);
Inc(i);
if i > High(ceg) then
Break;
end;
SetLength(ceg, i); // remove any empty slots.
CloseFile(f);
end;
Now you can put them into the TMemo:
for i := Low(ceg) to High(ceg) do
begin
Memo1.Lines.Add(Format('%s %s %d', [ceg[i].varosnev, ceg[i].termek, ceg[i].darabszam]));
end;
Note that the code above, reading from the file, assumes the file looks like:
3
Budapest tomato 23
Dublin tv 45
Rosslare projector 43
i.e. each "record" is on a line of its own and the first line contains the number of records.

InnoSetup making {app} dir for install.log

I need to create an install.log of the selected components in the install destination folder ({app}) but I'm getting in issue when i run that installer that says "File does not exist C:/tmp/exe/install.log" I'm assuming that means it has not created the dir "exe" yet. How can i circumvent this?
procedure CurStepChanged(CurStep: TSetupStep);
var
I: Integer;
LogList: TStringList;
begin
if CurStep = ssInstall then
begin
LogList := TStringList.Create;
try
LogList.Add('Selected components:');
for I := 0 to WizardForm.ComponentsList.Items.Count - 1 do
if WizardForm.ComponentsList.Checked[I] then
LogList.Add('Component: ' + WizardForm.ComponentsList.ItemCaption[I]);
LogList.SaveToFile(ExpandConstant('{app}\install.log'));
finally
LogList.Free;
end;
end;
end;
I suspect you're trying to access the folder too early in the process, before it's actually been created yet.
Try changing to a later step in the process, such as ssPostInstall. At that point, you'll know for certain that the folder has been created. The rest of your code should be able to stay the same.
procedure CurStepChanged(CurStep: TSetupStep);
var
I: Integer;
LogList: TStringList;
begin
if CurStep = ssPostInstall then
begin
LogList := TStringList.Create;
try
LogList.Add('Selected components:');
for I := 0 to WizardForm.ComponentsList.Items.Count - 1 do
if WizardForm.ComponentsList.Checked[I] then
LogList.Add('Component: ' + WizardForm.ComponentsList.ItemCaption[I]);
LogList.SaveToFile(ExpandConstant('{app}\install.log'));
finally
LogList.Free;
end;
end;
end;

Resources