![]() |
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? |
AW: Stream String lesen und schreiben
Am Einfachsten geht das mit "TStringStream.WriteString".
|
AW: Stream String lesen und schreiben
Oder probiere mal sowas:
Delphi-Quellcode:
MyStream.WriteBuffer(MyString[1], Length(MyString) * SizeOf(Char));
|
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} {-------------------------------} |
AW: Stream String lesen und schreiben
Zitat:
|
AW: Stream String lesen und schreiben
Zitat:
![]() .ReadData, .WriteData, .ReadBufferData usw. .WriteBufferData. ![]() ![]() ... |
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. |
AW: Stream String lesen und schreiben
Zitat:
|
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. |
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 ![]() |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:06 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz