[gelöst] TMemoryStream.ReadAnsiString fehlerhaft?

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

[gelöst] TMemoryStream.ReadAnsiString fehlerhaft?

Beitrag von Michl »

Servus,

Ich würde gern einem String den Inhalt eines TMemoryStreams direkt (über Umweg TStringList.Text gehts) übergeben. Dabei habe ich die Methode ReadAnsiString als dafür geeignet angesehen. Allerdings bekomme ich ein Stream read Error bei deren Verwendung.
Ich habe mir mal den Quellcode angesehen, sieht eigentlich verwendbar aus (kann leider nicht debuggen, da, wenn ich versuche die Unit Classes mit deren .inc in das Projekt einzufügen, es zur Fehlermeldung kommt: system.pp(40,2) Fatal: Can not open include file "systemh.inc").
Habe ich einen Ansatzfehler (Denkfehler) oder ist das ein Bug (Win7 64 Bit, Lazarus 1.3 r46545M FPC 2.7.1 i386-win32-win32/win64)?!

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
var
  MS: TMemoryStream;
  SL: TStringList;
  i: Integer;
  s: String;
begin
  MS:=TMemoryStream.Create;
  SL:=TStringList.Create;
  for i:=0 to 99 do MS.WriteByte(65);
  MS.Position:=0;
  SL.LoadFromStream(MS);           //das geht
  MS.Position:=0;
  Caption:=IntToStr(MS.ReadByte);  //das auch
  MS.Position:=0;
  s:=MS.ReadAnsiString;            //hier kommt es zum Stream read Error
//  Memo1.Lines.Text:=MS.ReadAnsiString;
  SL.Free;
  MS.Free;
end; 
Zuletzt geändert von Michl am Sa 18. Okt 2014, 23:34, insgesamt 1-mal geändert.

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

wp_xyz
Beiträge: 5143
Registriert: Fr 8. Apr 2011, 09:01

Re: TMemoryStream.ReadAnsiString fehlerhaft?

Beitrag von wp_xyz »

Das ist die Implementierung von ReadAnsiString:

Code: Alles auswählen

 
  Function TStream.ReadAnsiString : String;
   Var
    TheSize : Longint;
    P : PByte ;
  begin
    ReadBuffer (TheSize,SizeOf(TheSize));
    SetLength(Result,TheSize);
    // Illegal typecast if no AnsiStrings defined.
    if TheSize>0 then
     begin
       ReadBuffer (Pointer(Result)^,TheSize);
       P:=Pointer(Result)+TheSize;
       p^:=0;
     end;
   end;  
 
Wie erwartet liest der Stream zuerst die Stringlänge TheSize. Das ist ein LongInt. Du hast in den Stream aber 100x das Byte 65 = $41 geschrieben. Die Stringlänge ist daher die Zahl $41414141 = 1094795585. Kein Wunder, dass der Stream übers Ende gelesen wird. Schreibe einfach zuerst den LongInt 100 in den Stream (MS.WriteDWord(100)), dann geht's.

Oder, um einen Ansistring in den Stream zu schreiben, nimm einfach WriteAnsiString, das Gegenstück von ReadAnsiString.

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: TMemoryStream.ReadAnsiString fehlerhaft?

Beitrag von Michl »

Verstehe ich - sollte es für heute gut sein lassen. :wink:

Leider kann ich die Länge im TMemoryStream nicht als erstes setzen, da es von einer externen Methode kommt. Eine TStringList will ich aufgrund des Overheads aber nicht verwenden. Werde mir wohl eine eigene Funktion basteln.

Danke für die Mühe der Aufklärung und viele Grüße

Michael

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

exc-jdbi
Beiträge: 64
Registriert: So 3. Aug 2014, 03:37

Re: [gelöst] TMemoryStream.ReadAnsiString fehlerhaft?

Beitrag von exc-jdbi »

oder so, dass sollte ganz sicher gehen

Code: Alles auswählen

 
ms:=tMemoryStream.Create;
....
 
ms.Seek(0, soFromBeginning);
SetString(s,pAnsiChar(ms.Memory),ms.Size); //pAnsiChar wäre eine Möglichkeit
 

Freundliche Grüsse

exc-jdbi

wp_xyz
Beiträge: 5143
Registriert: Fr 8. Apr 2011, 09:01

Re: [gelöst] TMemoryStream.ReadAnsiString fehlerhaft?

Beitrag von wp_xyz »

Ist denn der ganze Memorystream für den String bestimmt? Dann geht's - für mich etwas lesbarer - auch so:

Code: Alles auswählen

 
function ReadStringFromFullStream(AStream: TStream): String;
begin
  SetLength(Result, AStream.Size);
  AStream.ReadBuffer(Result[1], AStream.Size);
end;
 

exc-jdbi
Beiträge: 64
Registriert: So 3. Aug 2014, 03:37

Re: [gelöst] TMemoryStream.ReadAnsiString fehlerhaft?

Beitrag von exc-jdbi »

Um einen String in den Buffer zu setzen geht sicher auch

Code: Alles auswählen

 
ms.WriteBuffer(Pointer(s)^,Length(s)); 
 
Ist aber sicher Geschmacksache :wink:

Freundliche Grüsse

exc-jdbi

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: [gelöst] TMemoryStream.ReadAnsiString fehlerhaft?

Beitrag von Michl »

Vielen Dank, habe ich auch so umgesetzt :)

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

Antworten