Marcol1no
Marcol1no

Reputation: 47

TFileStream write data to next line

I'm manipulating TFileStream and I want to write data to next line.

Following code rewrites the previous one...

What can I do to wrap and make it write the new line there?

function TParserSkyecc.GenerateHTMLFile(pathHtml,out1,out2,out3,out4,out5 : String) : Boolean;
var FS: TFileStream;
begin
  FS := TFileStream.Create(pathHtml+'\filename.txt',fmCreate or fmOpenWrite or fmShareDenyNone);
  try
  FS.Seek(0,soFromBeginning);
    FS.WriteBuffer(Pointer(AnsiString(out1))^,Length(out1));
    FS.WriteBuffer(Pointer(AnsiString(out2))^,Length(out2));
    FS.WriteBuffer(Pointer(AnsiString(out3))^,Length(out3));
    FS.WriteBuffer(Pointer(AnsiString(out4))^,Length(out4));
    FS.WriteBuffer(Pointer(AnsiString(out5))^,Length(out5));
  finally
    FS.Free;
  end;
end;

Upvotes: 0

Views: 2457

Answers (2)

Remy Lebeau
Remy Lebeau

Reputation: 595392

A simpler way to write this would be to use TStreamWriter instead of TFileStream directly. TStreamWriter takes a TEncoding in its constructor, and has a WriteLine() method. For example:

function TParserSkyecc.GenerateHTMLFile(pathHtml,out1,out2,out3,out4,out5 : String) : Boolean;
var
  Filename: string;
  Writer: TStreamWriter;
begin
  Result := False;
  try
    Filename := IncludeTrailingPathDelimiter(pathHtml) + 'filename.txt'; // or: TPath.Combine(pathHtml, 'filename.txt')
    Writer := TStreamWiter.Create(Filename, False, TEncoding.ANSI);
    try
      Writer.WriteLine(out1);
      Writer.WriteLine(out2);
      Writer.WriteLine(out3);
      Writer.WriteLine(out4);
      Writer.WriteLine(out5);
      Writer.Flush;
      Result := True;
    finally
      Writer.Free;
    end;
  except
  end;
end;

Alternatively, you can use TStringList instead:

function TParserSkyecc.GenerateHTMLFile(pathHtml,out1,out2,out3,out4,out5 : String) : Boolean;
var
  Filename: string;
  SL: TStringList;
begin
  Result := False;
  try
    Filename := IncludeTrailingPathDelimiter(pathHtml) + 'filename.txt'; // or: TPath.Combine(pathHtml, 'filename.txt')
    SL := TStringList.Create;
    try
      SL.Add(out1);
      SL.Add(out2);
      SL.Add(out3);
      SL.Add(out4);
      SL.Add(out5);
      SL.SaveToFile(Filename, TEncoding.ANSI);
      Result := True;
    finally
      SL.Free;
    end;
  except
  end;
end;

Upvotes: 3

HeartWare
HeartWare

Reputation: 8243

uses System.Classes, System.SysUtils, System.IOUtils;

VAR pathHtml : STRING;

PROCEDURE Test(CONST TXT : STRING);
  VAR
    FS  : TStream;
    N   : TFileName;
    B   : TBytes;

  BEGIN
    N:=TPath.Combine(pathHtml,'filename.txt');
    IF NOT TFile.Exists(N) THEN
      FS:=TFileStream.Create(N,fmCreate OR fmShareDenyNone)
    ELSE BEGIN
      FS:=TFileStream.Create(N,fmOpenWrite OR fmShareDenyNone);
      FS.Position:=FS.Size
    END;
    TRY
      B:=TEncoding.ANSI.GetBytes(TXT);
      FS.WriteBuffer(B,LENGTH(B))
    FINALLY
      FS.Free
    END
  END;

Comments to implementation:

  1. Use TPath.Combine to combine a directory and a File Name
  2. Use TEncoding.ANSI.GetBytes to convert a UNICODE String to ANSI. The version you use above is faulty, as the AnsiString equivalent of a UNICODE String can be of a different length than the UNICODE String, f.ex. when you have national characters that are encoded in UNICODE as a pair but in AnsiString as a single byte, so you might end up (attempting to) write more bytes than the AnsiString conversion produces.
  3. Be careful with AnsiString (and TEncoding.ANSI) as it is dependant on the language/region setting of the computer upon which the program is running.

If what Tom is saying in the comments: Asker wants to have the strings on separate lines in the file. is true, then it's quite simple. Just replace the lines

FS.WriteBuffer(Pointer(AnsiString(out1))^,Length(out1));
FS.WriteBuffer(Pointer(AnsiString(out2))^,Length(out2));
FS.WriteBuffer(Pointer(AnsiString(out3))^,Length(out3));
FS.WriteBuffer(Pointer(AnsiString(out4))^,Length(out4));
FS.WriteBuffer(Pointer(AnsiString(out5))^,Length(out5));

with

out1:=out1+#13#10; out2:=out2+#13#10; out3:=out3+#13#10;out4:=out4+#13#10; out5:=out5+#13#10;
FS.WriteBuffer(Pointer(AnsiString(out1))^,Length(out1));
FS.WriteBuffer(Pointer(AnsiString(out2))^,Length(out2));
FS.WriteBuffer(Pointer(AnsiString(out3))^,Length(out3));
FS.WriteBuffer(Pointer(AnsiString(out4))^,Length(out4));
FS.WriteBuffer(Pointer(AnsiString(out5))^,Length(out5));

to append a CR/LF to each line.

Upvotes: 1

Related Questions