Recent

Author Topic: TFileStream.ReadAnsiString/WriteAnsiString. Non-printable characters in files  (Read 1751 times)

simone

  • Hero Member
  • *****
  • Posts: 626
I want to read/write some information in a text file using TFileStream.ReadAnsiString/WriteAnsiString.

The drawback I encountered with this methods is that the generated files have the first 4 bytes with the length of every string that is read/written (as in documentation).

This implies that the generated files are not purely textual, having non-printable characters corresponding to the bytes that encode the length of strings.

Is there a way to overcome this inconvenience? Thanks in advance.
« Last Edit: November 28, 2023, 01:42:55 pm by simone »
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

Fibonacci

  • Hero Member
  • *****
  • Posts: 608
  • Internal Error Hunter
If you want to use ReadAnsiString then these 4 bytes are required, otherwise you wouldnt know how long is the string, and there can be multiple strings.

Use other methods, Read/Write or ReadBuffer/WriteBuffer.

Bart

  • Hero Member
  • *****
  • Posts: 5467
    • Bart en Mariska's Webstek
I want to read/write some information in a text file using TFileStream.ReadAnsiString/WriteAnsiString.
You're not treating that file as a text file then.
If you want it to be a text file, treat it as a text file.
Either use the TextFile type for the file and use read(ln)/write(ln), use a TStringList and use it's LoadFromFile/SaveToFile methods, or treat it as an untyped file and read into a buffer, parse the buffer, make changes, write the new buffer back to the file.
I personally would not advice the last one though.

Bart

simone

  • Hero Member
  • *****
  • Posts: 626
Yes, I know how to deal with text files, with the classic approach or with TStringList methods. In my context, I want to use streams because I need to save text files both in files and in memory. Streams, as well known, allow this type of needs to be managed in a unified way.

Since TStream.WriteAnsiString is virtual, while TStream.ReadAnsiString is not (why???), I can't override them to change their behavior. So, using class helpers, I devised this simple solution to manage purely textual (ansi) files with streams:

Code: Pascal  [Select][+][-]
  1. program project1;
  2. uses
  3.   Classes;
  4.  
  5. type
  6.  
  7.   { TStreamHelper }
  8.  
  9.   TStreamHelper=class helper for TStream
  10.     function ReadText:string;
  11.     procedure WriteText(const Text : string);
  12.   end;
  13.  
  14.  
  15. var
  16.   FileStream : TFileStream;
  17.  
  18. { TStreamHelper }
  19.  
  20. function TStreamHelper.ReadText:string;
  21. var
  22.   P : PByte;
  23. begin
  24.   Result:='';
  25.   SetLength(Result,Size);
  26.   Position:=0;
  27.   ReadBuffer(Pointer(Result)^,Size);
  28.   P:=Pointer(Result)+Size;
  29.   P^:=0;
  30. end;
  31.  
  32. procedure TStreamHelper.WriteText(const Text : string);
  33. begin
  34.   Position:=0;
  35.   WriteBuffer(Pointer(Text)^,Length(Text));
  36. end;
  37.  
  38. begin
  39.   //write test
  40.   FileStream:=TFileStream.Create('file.txt',fmCreate);
  41.   try
  42.     FileStream.WriteText('aaabbbccc');
  43.   finally
  44.     FileStream.Free;
  45.   end;
  46.  
  47.   //read test
  48.   FileStream:=TFileStream.Create('file.txt',fmOpenRead);
  49.   try
  50.     writeln(FileStream.ReadText);
  51.   finally
  52.     FileStream.Free;
  53.   end;
  54.  
  55.   readln;
  56. end.

« Last Edit: November 28, 2023, 11:15:45 pm by simone »
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
I need to save text files both in files and in memory.
Where do you think goes the data of a loaded TStringList when not in memory?
And for your code I suggest to use AnsiString/PAnsiChar type to be future compatible and to inform users of your code, what it really is compatible with.
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

jamie

  • Hero Member
  • *****
  • Posts: 6735
There is:

  TStringStream

With that, it builds a single data-String from any strings you write to it and there is no BIN header information stored.

At any point, you can use a TfileStream and load or copy this stream elsewhere, etc.
The only true wisdom is knowing you know nothing

simone

  • Hero Member
  • *****
  • Posts: 626
Where do you think goes the data of a loaded TStringList when not in memory?

The fact that a TStringList goes into memory has no relevance to my initial post. My context is that of a diagram editor. I use TFileStream to load/save diagrams from/to files and TMemoryStream to save states for the purpose of implementing undo/redo functions.

And for your code I suggest to use AnsiString/PAnsiChar type to be future compatible and to inform users of your code, what it really is compatible with.

Fair observation. I agree.

There is:

  TStringStream

With that, it builds a single data-String from any strings you write to it and there is no BIN header information stored.

At any point, you can use a TfileStream and load or copy this stream elsewhere, etc.

This is a good alternative to the approach I used.

Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

Bart

  • Hero Member
  • *****
  • Posts: 5467
    • Bart en Mariska's Webstek
In my context, I want to use streams because I need to save text files both in files and in memory. Streams, as well known, allow this type of needs to be managed in a unified way.

TStringList does have SaveToStream/LoadFromStream...

Bart

simone

  • Hero Member
  • *****
  • Posts: 626
You are right. What you propose is probably the simplest solution to the problem I described.
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

 

TinyPortal © 2005-2018