Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2009-10

Creating text files with TFileStream

21 messages · 10 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Graeme Geldenhuys

Hi,

How do you create plain text file output with TFileStream? Or is TFileStream reserved for binary output only?

I'm using TFileStream as follows;
  // helper function to simply things
  procedure writef(AText: string);
  begin
    AOut.WriteAnsiString(AText + LineEnding);
  end;

where AOut is the TFileStream. But if I view the output file, it "mostly" looks like text. Except that on each line in starts with some random 2-3 characters.

Maybe TFileStream is not suited for plain text output, and I should rather use the File type instead?

Regards, - Graeme - _______________________________________________ fpGUI - a cross-platform Free Pascal GUI toolkit http://opensoft.homeip.net/fpgui/
Gerard N/A
to Graeme Geldenhuys

Hi,

Graeme Geldenhuys wrote
where AOut is the TFileStream.  But if I view the output file, it "mostly" looks like text. Except that on each line in starts with some random 2-3 characters.

Could it be that the length indicator bytes of the string are written to the stream?

Maybe TFileStream is not suited for plain text output, and I should rather use the File type instead?

Did you try writing with WriteBuffer(Atext[1], length(AText)?

Regards,

Gerard

Marco van de Voort
to Gerard N/A

In our previous episode, Gerard N/A said:

Could it be that the length indicator bytes of the string are written to the stream?

I think his result is a shortstring, and that gets binarily written.

> Maybe TFileStream is not suited for plain text output, and I should > rather use the File type instead? Did you try writing with
  if length(atext)>0 then
WriteBuffer(Atext[1], length(AText)?
Graeme Geldenhuys
to Gerard N/A: On Fri, Oct 23, 2009 at 11:58 AM, Graeme Geldenhuys Could it be that the length indicator…

2009/10/23 Gerard N/A :

Could it be that the length indicator bytes of the string are written to the stream?

Ah, () implementation, you seem to be
100% correct.

  Procedure TStream.WriteAnsiString (const S : String);
  Var L : Longint;
  begin
    L:=Length(S);
    WriteBuffer (L,SizeOf(L));
    WriteBuffer (Pointer(S)^,L);
  end;

That function is then very deceiving - by doing something extra to what the method name suggests. Why is the writing of the string length as a prefix needed?

Did you try writing with WriteBuffer(Atext[1], length(AText)?

That works exactly like I intended. Thanks Gerard.

Regards, - Graeme - _______________________________________________ fpGUI - a cross-platform Free Pascal GUI toolkit http://opensoft.homeip.net/fpgui/
Graeme Geldenhuys
to Marco van de Voort: In our previous episode, Gerard N/A said: I think his result is a shortstring, and that…

2009/10/23 Marco van de Voort :

 if length(atext)>0 then >WriteBuffer(Atext[1], length(AText)?

I always add a LineEnding character to AText, so the 'if length()' check is not strictly needed. Sometimes I would like to write a "blank" line in my text output. Equivalent of writeln('');

Regards, - Graeme - _______________________________________________ fpGUI - a cross-platform Free Pascal GUI toolkit http://opensoft.homeip.net/fpgui/
Vincent Snijders
to Graeme Geldenhuys: 2009/10/23 Gerard N/A : Ah, () implementation, you seem to be 100% correct. Procedure…
Graeme Geldenhuys wrote 19 lines
2009/10/23 Gerard N/A : > Could it be that the length indicator bytes of the string are written > to the stream? Ah, () implementation, you seem to be 100% correct. Procedure TStream.WriteAnsiString (const S : String); Var L : Longint; begin L:=Length(S); WriteBuffer (L,SizeOf(L)); WriteBuffer (Pointer(S)^,L); end; That function is then very deceiving - by doing something extra to what the method name suggests. Why is the writing of the string length as a prefix needed?

Otherwise you cannot read it back. :-)

Vincent

Graeme Geldenhuys
to Graeme Geldenhuys: 2009/10/23 Gerard N/A : Ah, () implementation, you seem to be 100% correct. Procedure…

2009/10/23 Graeme Geldenhuys :

> Did you try writing with WriteBuffer(Atext[1], length(AText)? That works exactly like I intended. Thanks Gerard.

I spoke to soon! :-(

I can view the resulting output.txt file with Midnight Commander (Linux console file manager), but if I try and open that file with Gnome gEdit or Lazarus IDE, it says the file does not look like a text file and refuses to open it. :-(

How difficult could it be to write a damn text file! :-)

Regards, - Graeme - _______________________________________________ fpGUI - a cross-platform Free Pascal GUI toolkit http://opensoft.homeip.net/fpgui/
Graeme Geldenhuys
to Vincent Snijders: Otherwise you cannot read it back. :-) Vincent

2009/10/23 Vincent Snijders :

Otherwise you cannot read it back. :-)

But using .WriteAnsiString() doesn't create a plain text file, so the result is useless. And as my last post says, the method Gerard suggested is also not 100%.

It seems extra hard to create a normal, plain, standard text file with the TFileStream class. This should had this puzzle to a "Programming Olympiad" - it's tougher than one thinks.

Anyway, so now I'm back to square one - unable to create a plain text file with TFileStream. :-(

Regards, - Graeme - _______________________________________________ fpGUI - a cross-platform Free Pascal GUI toolkit http://opensoft.homeip.net/fpgui/
Henry Vermaak
to Graeme Geldenhuys

2009/10/23 Graeme Geldenhuys :

Show quoted text 15 lines
2009/10/23 Vincent Snijders : > > Otherwise you cannot read it back. :-) But using .WriteAnsiString() doesn't create a plain text file, so the result is useless. And as my last post says, the method Gerard suggested is also not 100%. It seems extra hard to create a normal, plain, standard text file with the TFileStream class.  This should had this puzzle to a "Programming Olympiad" - it's tougher than one thinks. Anyway, so now I'm back to square one - unable to create a plain text file with TFileStream. :-(

Maybe you need to put the line endings in manually?

Henry

Gerard N/A
to Graeme Geldenhuys: 2009/10/23 Graeme Geldenhuys : I spoke to soon! :-( I can view the resulting output.txt…
Graeme Geldenhuys wrote
I can view the resulting output.txt file with Midnight Commander (Linux console file manager), but if I try and open that file with Gnome gEdit or Lazarus IDE, it says the file does not look like a text file and refuses to open it. :-(
var
  AOut: TFileStream;
  s: String;
begin
  s:= '1234';
  AOut:= TFileStream.Create('C:\temp\aa.txt',fmCreate or fmOpenWrite);
  AOut.WriteBuffer(s[1], length(s));
  AOut.Free;

Strange, that works for me under Windows. I get a 4 byte text file containing '1234'.

Regards,

Gerard.

Vincent Snijders
to Graeme Geldenhuys: 2009/10/23 Vincent Snijders : But using .WriteAnsiString() doesn't create a plain text…
Graeme Geldenhuys wrote 16 lines
2009/10/23 Vincent Snijders : > Otherwise you cannot read it back. :-) But using .WriteAnsiString() doesn't create a plain text file, so the result is useless. And as my last post says, the method Gerard suggested is also not 100%. It seems extra hard to create a normal, plain, standard text file with the TFileStream class. This should had this puzzle to a "Programming Olympiad" - it's tougher than one thinks. Anyway, so now I'm back to square one - unable to create a plain text file with TFileStream. :-(

You want easy?

Then use

var
   outfile: text;
begin
   rewrite(outfile)';
   writeln(outfile, 'Line 1');
   writeln;
   writeln(outfile, 'Line 3');

But you want streams?

procedure WriteSomeText(S: TStream);
var
   Lines: TStrings;
begin
   Lines := TStringList.Create;
   Lines.Add('Line 1');
   Lines.Add();
   Lines.Add('Line 3');
   Lines.SaveToStream(s);
   Lines.Free;
end;

Vincent

Aleksa Todorovic
to Graeme Geldenhuys: 2009/10/23 Vincent Snijders : But using .WriteAnsiString() doesn't create a plain text…
Graeme Geldenhuys wrote
Anyway, so now I'm back to square one - unable to create a plain text file with TFileStream. :-(

What about:

TFileTextStream = class(TFileStream)
constructor Create...;
procedure WriteStr(const fmt: String; const args: array of const);
procedure WriteStr(const s: String);
end;
procedure TFileTextStream.WriteStr(const fmt: String; const args:
array of const);
var
  temp: String;
begin
  temp := Format(fmt, args);
  Write(temp[1], Length(temp));
end;
procedure TFileTextStream.WriteStr(const s: String);
begin
  WriteStr('%s', [s]);
end;

[written out of head, but it should work]

Aleksa Todorovic - Lead Programmer Eipix Entertainment http://www.eipix.com/
Vincent Snijders
to Graeme Geldenhuys: 2009/10/23 Vincent Snijders : But using .WriteAnsiString() doesn't create a plain text…
Graeme Geldenhuys wrote 5 lines
2009/10/23 Vincent Snijders : > Otherwise you cannot read it back. :-) But using .WriteAnsiString() doesn't create a plain text file, so the result is useless.

Is useless for your current use, I admit. Don't use it to create a plain text file.

But if you want write ansistrings in a stream and read them back, you need to know how much to read until the end.

Vincent

Henry Vermaak
to Graeme Geldenhuys: 2009/10/23 Henry Vermaak : What do you mean? I already append LineEnding to AText, and…

2009/10/23 Graeme Geldenhuys :

Show quoted text 6 lines
2009/10/23 Henry Vermaak : > > Maybe you need to put the line endings in manually? What do you mean?  I already append LineEnding to AText, and send that to WriteAnsiString() call.

That's what I meant (and I just realised you already mentioned it in a previous email, my bad). Have you tried using hexdump on the files you created to see what it's writing?

Henry

Frank Peelo
to Graeme Geldenhuys: 2009/10/23 Graeme Geldenhuys : I spoke to soon! :-( I can view the resulting output.txt…
Graeme Geldenhuys wrote 15 lines
2009/10/23 Graeme Geldenhuys : >>Did you try writing with WriteBuffer(Atext[1], length(AText)? > >That works exactly like I intended. Thanks Gerard. I spoke to soon! :-( I can view the resulting output.txt file with Midnight Commander (Linux console file manager), but if I try and open that file with Gnome gEdit or Lazarus IDE, it says the file does not look like a text file and refuses to open it. :-( How difficult could it be to write a damn text file! :-)

If you want a text file, why do you not use a variable of type text, instead of a TFileStream? Text is what writes a text file. I think these streams are for saving object state, which means they are binary files -- they only look like partial text files if the contents of the object looks partially like text. Trying to get them to do text files would be like trying to teach a pig to sing.

FP

JoshyFun
to Frank Peelo: If you want a text file, why do you not use a variable of type text, instead of a…

Hello Frank,

Friday, October 23, 2009, 12:50:22 PM, you wrote:

FP> If you want a text file, why do you not use a variable of type text, FP> instead of a TFileStream? Text is what writes a text file. I think these FP> streams are for saving object state, which means they are binary files

TFileStream, or in general TStream is much more versatile and powerful than any kind of type based pascal Text file. They are binary streams, yes, but that's exactly its power and as you can derive any class from TStream you can add the methods to access them as plain text files without any problem, the inverse is almost impossible.

FP> -- they only look like partial text files if the contents of the object FP> looks partially like text. Trying to get them to do text files would be FP> like trying to teach a pig to sing.

Since Delphi first streams I had never used pascal "files" anymore, they are a lot of restrictive, not thread safe and are very tied to which they expect to read/write.

Graeme's problem seems to be that he is writting UTF-8 text files without UTF-8 BOM. If the text presents high ascii chars the file will look to not text to some "inteligent" editors.

Best regards, JoshyFun
Mattias Gärtner
to Graeme Geldenhuys: 2009/10/23 Graeme Geldenhuys : I spoke to soon! :-( I can view the resulting output.txt…

Zitat von Graeme Geldenhuys :

Show quoted text 12 lines
2009/10/23 Graeme Geldenhuys : > >> Did you try writing with WriteBuffer(Atext[1], length(AText)? > > That works exactly like I intended. Thanks Gerard. I spoke to soon! :-( I can view the resulting output.txt file with Midnight Commander (Linux console file manager), but if I try and open that file with Gnome gEdit or Lazarus IDE, it says the file does not look like a text file and refuses to open it. :-(

It means your AText string contains special characters (#0..#8,#11,#14..#31)

How difficult could it be to write a damn text file! :-)

It's damn simple.
Use TFileStream if you want write one string.
Use a TStringList if you want to write several strings.

Mattias

Graeme Geldenhuys
to Aleksa Todorovic: On Fri, Oct 23, 2009 at 12:25, Graeme Geldenhuys What about: TFileTextStream =…

2009/10/23 Aleksa Todorovic :

constructor Create...; procedure WriteStr(const fmt: String; const args: array of const); procedure WriteStr(const s: String);

OK, I managed to solve the problem. I have two units that write to the output text file. The one unit I fixed by using
"AOut.WriteBuffer(s[1], length(s));" syntax, but the file was still causing issues when opening with gEdit or Lazarus IDE.

Evenually I found the problem. I forgot to change the other unit that also writes the the file, to use the new .WriteBuffer() syntax. Now the file generate seems to be plain text.

Thanks for everybody's help.

Regards, - Graeme - _______________________________________________ fpGUI - a cross-platform Free Pascal GUI toolkit http://opensoft.homeip.net/fpgui/
Graeme Geldenhuys
to JoshyFun: FP> If you want a text file, why do you not use a variable of type text, FP> instead of a…

2009/10/23 JoshyFun :

Since Delphi first streams I had never used pascal "files" anymore, they are a lot of restrictive, not thread safe and are very tied to which they expect to read/write.

That's kind-of why I wanted to use TFileStream. I use it for reading binary data, and thought to use it for writing text data. I always used to use Text type though.

Graeme's problem seems to be that he is writting UTF-8 text files without UTF-8 BOM. If the text presents high ascii chars the file will look to not text to some "inteligent" editors.

The problem was a rogue WriteAnsiString() line in another unit which wrote the string length before the text. And because that was the first line in the output file, it seems to have confused most text editors. Changing all the lines to use the correct .Write() call and parameter syntax, everything is working fine now.

Regards, - Graeme - _______________________________________________ fpGUI - a cross-platform Free Pascal GUI toolkit http://opensoft.homeip.net/fpgui/