Fabrizio
Fabrizio

Reputation: 8043

How do I prevent TStrings.SaveToFile creating a final empty line?

I have a file .\input.txt like this:

aaa
bbb
ccc

If I read it using TStrings.LoadFromFile and write it back (even without applying any changes) using TStrings.SaveToFile, it creates an empty line at the end of the output file.

var
  Lines : TStrings;
begin
  Lines := TStringList.Create;
  try
    Lines.LoadFromFile('.\input.txt');

    //...

    Lines.SaveToFile('.\output.txt');
  finally
    Lines.Free;
  end;
end;

The same behavior can be observed using the TStrings.Text property which will return a string containing an empty line at its end.

Upvotes: 9

Views: 1863

Answers (3)

davornik
davornik

Reputation: 31

How about:

Lines.Text:=Trim(Lines.Text);

Upvotes: 0

Fabrizio
Fabrizio

Reputation: 8043

For Delphi 10.1 (Berlin) or newer, the best solution is described in Uwe's answer.

For older Delphi versions, I found a solution by creating a child class of TStringList and overriding the TStrings.GetTextStr virtual function but I will be glad to know if there is a better solution or if someone else found something wrong in my solution

Interface:

  uses
    Classes;

  type
    TMyStringList = class(TStringList)
    private
      FIncludeLastLineBreakInText : Boolean;
    protected
      function GetTextStr: string; override;
    public
      constructor Create(AIncludeLastLineBreakInText : Boolean = False); overload;
      property IncludeLastLineBreakInText : Boolean read FIncludeLastLineBreakInText write FIncludeLastLineBreakInText;
    end;

Implementation:

uses
  StrUtils;      

constructor TMyStringList.Create(AIncludeLastLineBreakInText : Boolean = False);
begin
  inherited Create;

  FIncludeLastLineBreakInText := AIncludeLastLineBreakInText;
end;

function TMyStringList.GetTextStr: string;
begin
  Result := inherited;

  if(not IncludeLastLineBreakInText) and EndsStr(LineBreak, Result)
  then SetLength(Result, Length(Result) - Length(LineBreak));
end;

Example:

procedure TForm1.Button1Click(Sender: TObject);
var
  Lines : TStrings;
begin
  Lines := TMyStringList.Create();
  try
    Lines.LoadFromFile('.\input.txt');
    Lines.SaveToFile('.\output.txt');
  finally
    Lines.Free;
  end;
end;

Upvotes: 1

Uwe Raabe
Uwe Raabe

Reputation: 47694

For Delphi 10.1 and newer there is a property TrailingLineBreak controlling this behavior.

When TrailingLineBreak property is True (default value) then Text property will contain line break after last line. When it is False, then Text value will not contain line break after last line. This also may be controlled by soTrailingLineBreak option.

Upvotes: 17

Related Questions