AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Stream String lesen und schreiben

Ein Thema von stahli · begonnen am 1. Okt 2023 · letzter Beitrag vom 1. Okt 2023
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.343 Beiträge
 
Delphi 11 Alexandria
 
#1

Stream String lesen und schreiben

  Alt 1. Okt 2023, 12:20
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?
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
Benutzerbild von Olli73
Olli73

Registriert seit: 25. Apr 2008
Ort: Neunkirchen
741 Beiträge
 
#2

AW: Stream String lesen und schreiben

  Alt 1. Okt 2023, 12:39
Am Einfachsten geht das mit "TStringStream.WriteString".
  Mit Zitat antworten Zitat
Benutzerbild von Olli73
Olli73

Registriert seit: 25. Apr 2008
Ort: Neunkirchen
741 Beiträge
 
#3

AW: Stream String lesen und schreiben

  Alt 1. Okt 2023, 12:51
Oder probiere mal sowas:

MyStream.WriteBuffer(MyString[1], Length(MyString) * SizeOf(Char));
  Mit Zitat antworten Zitat
Andreas13

Registriert seit: 14. Okt 2006
Ort: Nürnberg
719 Beiträge
 
Delphi XE5 Professional
 
#4

AW: Stream String lesen und schreiben

  Alt 1. Okt 2023, 13:32
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}
{-------------------------------}
Grüße, Andreas
Wenn man seinem Nächsten einen steilen Berg hinaufhilft, kommt man selbst dem Gipfel näher. (John C. Cornelius)
  Mit Zitat antworten Zitat
peterbelow

Registriert seit: 12. Jan 2019
Ort: Hessen
702 Beiträge
 
Delphi 12 Athens
 
#5

AW: Stream String lesen und schreiben

  Alt 1. Okt 2023, 15:15
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.
Peter Below
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.088 Beiträge
 
Delphi 12 Athens
 
#6

AW: Stream String lesen und schreiben

  Alt 1. Okt 2023, 16:40
Zitat:
Stream String lesen und schreiben
Ähhhhhh, was ergbibt wohl String+Stream?

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

Delphi-Referenz durchsuchenTFile.ReadAllText

Delphi-Referenz durchsuchenTStringList

...
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu ( 1. Okt 2023 um 16:45 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.343 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: Stream String lesen und schreiben

  Alt 1. Okt 2023, 17:08
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. )

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.
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.462 Beiträge
 
Delphi 12 Athens
 
#8

AW: Stream String lesen und schreiben

  Alt 1. Okt 2023, 17:10
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.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.343 Beiträge
 
Delphi 11 Alexandria
 
#9

AW: Stream String lesen und schreiben

  Alt 1. Okt 2023, 17:13
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.
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.088 Beiträge
 
Delphi 12 Athens
 
#10

AW: Stream String lesen und schreiben

  Alt 1. Okt 2023, 17:34
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).
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:03 Uhr.
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