![]() |
Blöde Frage zum Speichern von Strings in Streams
Hallo,
ersteinmal mein Code:
Delphi-Quellcode:
Ich stand vor dem Problem, dass ich unter bestimmten Umständen einen String (mit unbekannter Länge) abspeichern muss. Dies habe ich gemacht und mich dann gewundert, warum beim Laden immer nur der halbe String korrekt war und der hintere Teil komische Zeichen enthielt. Also habe ich ein wenig rumprobiert und am Ende einfach die Zeile
procedure TTeTrades.SaveToFile;
var f: TFileStream; str_size, i: Integer; d: TTeStaticValues; name: String; begin header.count := data.Count; f := TFileStream.Create(FConfig.folders.tradesdata + '\' + string(header.name) + '.te', fmCreate); //Header schreiben f.Write(header,SizeOf(header)); //Daten schreiben for i := 0 to data.Count-1 do begin d := data[i].stat; f.Write(d,SizeOf(d)); if (d.item_id = 0) then begin //Name schreiben wenn CustomItem name := data[i].name; str_size := Length(name); f.Write(str_size, SizeOf(str_size)); f.Write(name[1],2*str_size); // <---- WICHTIG end; end; f.Free; end; procedure TTeTrades.LoadFromFile; var f: TFileStream; i: Integer; name: String; str_size: Integer; s: TTeStaticValues; begin data.Clear; f := TFileStream.Create(FConfig.folders.tradesdata + '\' + string(header.name) + '.te', fmOpenRead); //Header lesen f.Read(header,SizeOf(header)); //Daten lesen for i := 0 to header.count -1 do begin name := ''; f.Read(s,SizeOf(s)); if s.item_id = 0 then begin //Name lesen wenn CustomItem f.Read(str_size,SizeOf(str_size)); SetLength(name,str_size); f.Read(name[1],str_size); end; Add(name,s); end; f.Free; end;
Delphi-Quellcode:
die in meinen Augen total logisch ist zu
f.Write(name[1],str_size);
Delphi-Quellcode:
geändert. Danach hat alles funktioniert. Die Frage ist nur, warum da der Faktor 2 enthalten sein muss, da ich ihn beim Auslesen ja in keinster Weise brauche.
f.Write(name[1],2*str_size);
Ich würde das einfach gern verstehen, um Folgefehler zu vermeiden. Deshalb schonmal 10000 Dank im Voraus Delphi Version : XE8 Debug 32Bit EDIT: Eine Sache funktioniert leider nicht gut: Beinhaltet der String Sonderzeichen bekomme ich Probleme. Mein Test: String: Text mit Leerzeichen und Sôndérzèichen° Binäre Datei mit Editor geöffnet beinhaltet:
Code:
Geladen wird allerdings 'Text mit Leerzeichen'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'e '
std ' T e x t m i t L e e r z e i c h e n u n d S ô n d é r z è i c h e n °
Das heißt für mich: Das speichern der Sonderzeichen geht, das laden aber nicht.. warum? |
AW: Blöde Frage zum Speichern von Strings in Streams
Da wirst du wohl mit Unicode deine Probleme haben. Ermittle doch einfach die Länge des Strings und nimm diesen Wert zum Speichern des Strings.
|
AW: Blöde Frage zum Speichern von Strings in Streams
Hast du dir meinen Code überhaupt angeschaut? Ich ermittel die Länge des Strings zum abspeichern..
|
AW: Blöde Frage zum Speichern von Strings in Streams
Jo, nun musst du sie nur noch richtig benutzen :stupid:
Seit Unicode (also Delphi 2009) sind die Strings Unicode. Damit ist es vorbei mit 1 Buchstabe = 1 Byte. Die Buchstaben heißen jetzt allgemeiner "Code Point" (vereinfacht) und belegen je nach Kodierung 1-4 Bytes oder so. Der String in Delphi benutzt vermutlich UCS-16, also 1 Codepoint = 2 Bytes in den meisten Fällen. Daher deine 2 mit der du multiplizierst: Die Stringlänge wird in Codepoints angegeben, der Stream erwartet aber eine Länge in Bytes! Vernünftiger wäre es daher, die Stringlänge mit
Delphi-Quellcode:
zu multiplizieren. Und zwar beim lesen und schreiben.
sizeof(char)
P.S.: Wenn du mal ein paar japanische Zeichen (z.B.: 日本国 ) in deinen String tust, dann werden im Hexeditor auch die "Leerzeichen" befüllt ;-) |
AW: Blöde Frage zum Speichern von Strings in Streams
Danke @jfheins
du bist der Hammer! Hat sehr geholfen deine Antwort. Habe den Sonderzeichenstring aus meinem EDIT benutzt und hat tadellos funktioniert. Für mich ist das das erste Mal, dass ich mit binärem Schreiben von Dateien arbeite und habe mir das Wissen mit "alten" Beispielen angeeignet, daher kommt meine Unwissenheit! Daher vielen Dank für die schnelle, kurze und präzise Antwort :) |
AW: Blöde Frage zum Speichern von Strings in Streams
Zitat:
|
AW: Blöde Frage zum Speichern von Strings in Streams
Also gut... Wenn es den unbedingt Ansi/Unicode Strings seien müssen, dann muss man eben den Aufwand machen.
Mit ShortStrings könnte man einfach einen ganzen Record in einem Rutsch schreib was natürlich viel schneller ist... Aber wenn Stream dann doch einfach so was nehmen...:
Delphi-Quellcode:
Das mache ich 1x richtig und brauch mich nie wieder darum zu kümmern.
TMyStreamIO = class
private MS : TMemoryStream; public constructor Create; destructor Destroy;Override; Procedure AddHeader(Version:integer); Function GetHeader:Integer; Procedure Schreibe(V:Integer);overload; Procedure Schreibe(V:Boolean);overload; Procedure Schreibe(V:Byte);overload; Procedure Schreibe(V:AnsiChar);overload; Procedure Schreibe(V:Char);overload; Procedure Schreibe(V:Word);overload; Procedure Schreibe(V:Int64);overload; Procedure Schreibe(V:Shortstring);overload; Procedure Schreibe(V:AnsiString);overload; Procedure Schreibe(V:String);overload; Procedure Schreibe(V:TDateTime);overload; Procedure Schreibe(V:TStream);overload; Procedure Schreibe(Var ALL;Size:Integer);overload; Function Lese(Var V:Integer):boolean;overload; Function Lese(Var V:Boolean):boolean;overload; Function Lese(Var V:Byte):boolean;overload; Function Lese(Var V:AnsiChar):boolean;overload; Function Lese(Var V:Char):boolean;overload; Function Lese(Var V:Word):boolean;overload; Function Lese(Var V:Int64):boolean;overload; Function Lese(Var V:Shortstring):boolean;overload; Function Lese(Var V:AnsiString):boolean;overload; Function Lese(Var V:String):boolean;overload; Function Lese(Var V:TDateTime):boolean;overload; Function Lese(Var V:TStream):boolean;overload; Function Lese(Var ALL;Size:Integer):boolean;overload; Function PackenDaten:TByteDynArray; Procedure EndPackeDaten(Var Data:TByteDynArray); Procedure Skipp(I:Int64); Function EOF:boolean; end; Und ganz wichtig der Sourcecode bleib lesbar. |
AW: Blöde Frage zum Speichern von Strings in Streams
Zitat:
Delphi-Quellcode:
und
TBinaryWriter
Delphi-Quellcode:
aus System.Classes.
TBinaryReader
|
AW: Blöde Frage zum Speichern von Strings in Streams
Zitat:
Und meine Klasse kann den Stream vorher noch Packen... Und wirft keine Exceptions :stupid: Und liefert mir ein praktisches TByteDynArray das ich perfekt per Soap versenden kann... Aber im Prinzip hast Du natürlich recht... |
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:19 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