Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Stream String lesen und schreiben (https://www.delphipraxis.net/213819-stream-string-lesen-und-schreiben.html)

stahli 1. Okt 2023 11:20

Stream String lesen und schreiben
 
Ich finde keine aktuellen Infos und oute mich als doof... :-(

Wie schreibt und liest man aktuell Strings in aus aus Streams?

Ich dachte TStream.WriteData(S) und TStream.ReadData(S) sollten vom Compiler (inzwischen) generisch aufgelöst werden?
Compiliert wird das auch fehlerfrei, es wird abwer nur der Pointer gespeichert.

Mache ich etwas falsch?
Habe ich die generische Erweiterung falsch interpretiert?
Ist das ein Bug?

Wie macht man´s heute richtig?
Ich dachte Umwege über Buffergröße usw. sollten nicht mehr nötig sein?

Olli73 1. Okt 2023 11:39

AW: Stream String lesen und schreiben
 
Am Einfachsten geht das mit "TStringStream.WriteString".

Olli73 1. Okt 2023 11:51

AW: Stream String lesen und schreiben
 
Oder probiere mal sowas:

Delphi-Quellcode:
MyStream.WriteBuffer(MyString[1], Length(MyString) * SizeOf(Char));

Andreas13 1. Okt 2023 12:32

AW: Stream String lesen und schreiben
 
Hallo Stahli,

ich benutze folgeden Code um die Inhalte divereser dynamischer Arrays (= "Vektoren") als AnsiString in Streams zu speichern und aus diesen daraus zu laden:
Delphi-Quellcode:
Type
  TDynStringVektor = TArray<String>;
  PDBiA_StreamType = Int32;

CONST
  PDBiA_StreamType_Integer    = 32000;
  PDBiA_StreamType_Double     = PDBiA_StreamType_Integer + 200;
  PDBiA_StreamType_Extended   = PDBiA_StreamType_Integer + 400;
  PDBiA_StreamType_String     = PDBiA_StreamType_Integer + 600;
  PDBiA_StreamType_MPAF_String = PDBiA_StreamType_Integer + 800;
  ...

Procedure WriteStringVektor_To_Stream(CONST Quelle: TDynStringVektor; Stream: TBytesStream);
// Dynamisches String-Array in einen Stream umwandeln

{ Struktur des Streams, der nur Byte-weise gelesen werden kann:

  ----------------------
  0. StreamType          : Int32 (nach eigener Definition)
  ----------------------
  1. Länge des Arrays    : Int32
  ----------------------
  2. Länge von String_1   : Int32
  3. String_1             : String variabler Länge
  ----------------------
  4. Länge von String_2   : Int32
  5. String_2             : String variabler Länge
  ----------------------
  6. Länge von String_3   : Int32
  7. String_3             : String variabler Länge
  ----------------------
    ...
    ...
  ----------------------
 
  n-1. Länge vom LETZTEN String  : Int32
  n.  LETZTER String            : String variabler Länge
  ----------------------
}


VAR
  Len      : Int32;
  StreamType: PDBiA_StreamType;
  S        : AnsiString;
   
Begin
  Stream.Position:= 0; // Wichtig!! 
 
  StreamType:= PDBiA_StreamType_String;

  Stream.WriteBuffer(StreamType, SizeOf(StreamType)); // Header-Eintrag (= Int32) im Stream: StreamTyp
 
  Len:= Length(Quelle);
  Stream.WriteBuffer(Len, SizeOf(Len));  // Erster Eintrag (= Int32) im Stream: Länge des Arrays:

  IF Len < 0 Then Begin // Fehlerhafter Eintrag im Stream
    Fehlermeldung('Stream-Fehler: Negative Array-Länge!');
    Exit;
  End;
 
  IF Len = 0 Then // Leeres Array:
    Exit;        // Fertig --> Es wird nur die Länge (= 0) in den Stream geschrieben, mehr nicht!
   
  For S in Quelle Do Begin               // Für jeden String im String-Array wiederholen
    Len:= Length(S);                     // Strings werden der Reihe nach eingelesen
    Stream.WriteBuffer(Len, SizeOf(Len)); // Länge des aktuellen Strings (dynamisch: d.h. jedes Element könnte unterschiedlich lang sein)

    IF Len <> 0 Then Begin
      Stream.WriteBuffer(S[1], Len*SizeOf(S[1])); // String speichern. Zählung bei Strings: 1-basiert! Daher S[1] --> Erstes Zeichen im dynamischen String
    End;
  End;
End;{WriteStringVektor_To_Stream}
{-------------------------------}

Function LoadStingVektor_From_Stream(Stream: TBytesStream): TDynStringVektor;
// Dynamisches String-Array aus einem Stream laden

{ Struktur des Streams, der nur Byte-weise gelesen werden kann:

  ----------------------
  0. StreamType          : Int32 (nach eigener Definition)
  ----------------------
  1. Länge des Arrays    : Int32
  ----------------------
  2. Länge von String_1   : Int32
  3. String_1             : String variabler Länge
  ----------------------
  4. Länge von String_2   : Int32
  5. String_2             : String variabler Länge
  ----------------------
  6. Länge von String_3   : Int32
  7. String_3             : String variabler Länge
  ----------------------
    ...
    ...
  ----------------------
 
  n-1. Länge vom LETZTEN String  : Int32
  n.  LETZTER String            : String variabler Länge
  ----------------------
}

VAR
  i, Len   : Int32;
  StreamType: PDBiA_StreamType;
 
Begin
  Stream.Position:= 0; // Wichtig!!

  Stream.ReadBuffer(StreamType, SizeOf(StreamType)); // Header-Eintrag (= Int32) im Stream: StreamTyp


  Len:= SizeOf(Len);
  Stream.ReadBuffer(Len, Len); // Erster Eintrag (= Int32) im Stream: Länge des Arrays:

  IF Len < 0 Then Begin // Fehlerhafter Eintrag im Stream
    Fehlermeldung('Stream-Fehler: Negative Array-Länge!');
    Exit;
  End;

  IF Len = 0 Then Begin // Leeres Array:
    Exit;               // Fertig --> Es stand nur die Länge (= 0) in den Stream geschrieben, mehr nicht!
  End;

  SetLength(Result, Len);
 
  For i:= 0 To Len-1 Do Begin// 0: dynamisches Array ist NULL-basiert!
    Stream.ReadBuffer(Len, SizeOf(Len)); // Länge des aktuellen Strings (dynamisch: d.h. jedes Element könnte unterschiedlich lang sein)

    IF Len < 0 Then Begin // Fehlerhafter Eintrag im Stream
      Fehlermeldung('Stream-Fehler: Negative String-Länge!');
      Exit;
    End;

   IF Len > 0 Then Begin
     SetLength(Result[i], Len);
     Stream.ReadBuffer(Result[i][1], Len*SizeOf(Char)); // 1: ERSTES Zeichen des Strings
   End;
  End;
End;{LoadStingVektor_From_Stream}
{-------------------------------}

peterbelow 1. Okt 2023 14:15

AW: Stream String lesen und schreiben
 
Zitat:

Zitat von stahli (Beitrag 1527572)
Ich finde keine aktuellen Infos und oute mich als doof... :-(

Wie schreibt und liest man aktuell Strings in aus aus Streams?

Hängt von der Struktur der Daten ab. Wenn es [B]nur[B] strings sind pack sie in eine TStringlist und nutze deren SaveToStream und LoadFromStream-Methoden. Wenn es ein Mix von Datentypen ist verwende die diversen Methoden von TStream die intern auch vom TComponent-Streaming verwendet werden. Es gibt für jeden Datentyp zugehörige Read und Write-Methoden, jedes Item wird mit einem den Typ identifizierenden Tag und der Datengröße geschrieben, so daß man auch beim Lesen bestimmen kann, was da als nächstes kommt. Wenn es nicht unbedingt ein binärer Stream sein muß kann man sich für seine Daten auch ein XML oder JSON-Format schnitzen, jedenfalls wenn das Format der Daten konstant ist.

himitsu 1. Okt 2023 15:40

AW: Stream String lesen und schreiben
 
Zitat:

Stream String lesen und schreiben
Ähhhhhh, was ergbibt wohl String+Stream? :roll:

Delphi-Referenz durchsuchenTStringStream .DataString bzw. .ReadString, .WriteString,
.ReadData, .WriteData, .ReadBufferData usw. .WriteBufferData.

Delphi-Referenz durchsuchenTFile.ReadAllText

Delphi-Referenz durchsuchenTStringList

...

stahli 1. Okt 2023 16:08

AW: Stream String lesen und schreiben
 
Vielen Dank allen.

Ich war der Meinung, Emba hätte das mal einheitlich umgesetzt und eine generische Compilermagie eingebaut.
Na ja...

Ich habe mir jetzt eine kleine Unit gebaut, die den MemoryStream um zwei Funktionen erweitert.

Dazu einfach in allen Units, die die Streamfunktionalität brauchen, die Unit nach der SystemClasses einbinden:
(Ich vergesse immer wieder, die diese Klassen-Ersetzung heißt. :oops:)

Lieber Wäre mir zwar, WriteData<String>() und ReadData<String>() zu erweitern (um einfach immer diese Methoden nutzen zu können) aber habe keine Ahnung, ob das umsetzbar und dann auch stabil wäre...
Mit dem Workaround hier kann ich aber schon ganz gut leben.


Delphi-Quellcode:
unit MyUnit;

interface

  uses

    System.Classes, MyMemoryStream, // <----------------
    Generics.Collections, System.SyncObjs,
    Winapi.MMSystem;

  type


Delphi-Quellcode:
unit MyMemoryStream;

interface

  uses

    System.Classes;

  type

    TMemoryStream = class(System.Classes.TMemoryStream)
    public
      procedure ReadString(var aString: String);
      procedure WriteString(const aString: String);
    end;

implementation

  {: ************************************* TMemoryStream ************************************ :}

  {: ---------------------------------------- public ---------------------------------------- :}

  procedure TMemoryStream.ReadString(var aString: String);
  var
    Reader: TBinaryReader;
  begin
    Reader := TBinaryReader.Create(Self);
    try
      aString := Reader.ReadString;
    finally
      Reader.Free;
    end;
  end;

  procedure TMemoryStream.WriteString(const aString: String);
  var
    Writer: TBinaryWriter;
  begin
    Writer := TBinaryWriter.Create(Self);
    try
      Writer.Write(aString);
    finally
      Writer.Free;
    end;
  end;

end.

Uwe Raabe 1. Okt 2023 16:10

AW: Stream String lesen und schreiben
 
Zitat:

Zitat von stahli (Beitrag 1527572)
Ich dachte TStream.WriteData(S) und TStream.ReadData(S) sollten vom Compiler (inzwischen) generisch aufgelöst werden?

...

Ich dachte Umwege über Buffergröße usw. sollten nicht mehr nötig sein?

Ein String hat nun mal eine variable Länge und die muss irgendwie bekannt sein. Das geht entweder in dem man immer einen festen Wert verwendet, der dann beim Lesen bekannt ist, oder man schreibt den Wert mit in den String - in der Regel vor den Zeichen. Das ist aber eine Konvention und die kann nicht generisch gelöst werden, da es keinen intrinsischen Ansatz wie bei den fixen Datentypen dafür gibt.

stahli 1. Okt 2023 16:13

AW: Stream String lesen und schreiben
 
Aber der Compiler weiß ja, was da für Typen rein gehen.
Insofern könnte er dann im Fall eines "String" auf meine Funktion umleiten und die Länge und Inhalt schreiben bzw. lesen.

himitsu 1. Okt 2023 16:34

AW: Stream String lesen und schreiben
 
Woher soll er wissen, dass die Länge gespeichert werden soll?
Man könnte ja auch als PChar 0-terminiert speichern.

Aber ja, man könnte natürlich ein ReadData/WriteData, bzw. ReadBufferData/WriteBufferData mit einem String-Typen bauen,
aber wie groß soll dann die Größe gespeichert werden?
Byte/Word/LongWord

Delphi-Referenz durchsuchenTReader/TWriter speichern den Typen und beim String auch die Länge, mit unterschiedlichen StringTypen (ShortString bis länger).


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:15 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz