Autor |
Beitrag |
Narses
      

Beiträge: 10183
Erhaltene Danke: 1256
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: Do 12.07.12 17:13
Moderiert von Narses: Abgetrennt von [url=www.entwickler-ecke....3#665563]hier[/url].
Moin!
jaenicke hat folgendes geschrieben : | Was ich mich frage ist, warum immer wieder mit Strings als Datencontainern angefangen wird. Die sind dafür schlicht nicht gedacht. |
Das ist schon richtig, aber es sind halt schöne magische dynamische Arrays mit einfachen Operatoren.  Mach mal Str1 := Str2 +Str3; mit Streams nach, da brauchst du aber mehr als eine Zeile (nicht unbedingt grandios intuitiven) Code für...  Vom Erzeugen/Freigeben der Objekte gar nicht zu reden.
Wenn ich ehrlich bin: ich finde auch heute (in bestimmten Situationen) noch AnsiStrings als Datenlager vielleicht konzeptionell nicht ideal, aber absolut angemessen und brauchbar.
Beim Missbrauch visueller Komponenten als Datenlager gibt´s nix schönzureden (ausser vielleicht noch als Lernschritt bei Anfängern). Ob die Strings hier im Thread angemessen sind, kann ich nicht beurteilen, dazu habe ich zu wenig vom Einsatzzweck verstanden. (Anm.: Das bezog sich auf den Ursprungsthread, s.o.) Trotzdem wäre ich mal vorsichtig mit den pauschalen Verdammnis-Sprüchen.
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
Zuletzt bearbeitet von Narses am Fr 13.07.12 12:51, insgesamt 4-mal bearbeitet
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Do 12.07.12 17:58
Narses hat folgendes geschrieben : | Das ist schon richtig, aber es sind halt schöne magische dynamische Arrays mit einfachen Operatoren.  |
Eben nicht. Solange man ausschließlich in einer bestimmten Codepage arbeitet, merkt man das vielleicht nicht, aber was nicht jedem klar ist:
In jedem AnsiString ist (neben dem Referenzzähler, der Größe des einzelnen Zeichens und der Länge des Strings) gespeichert in welcher Codepage er vorliegt (12 Byte vor dem ersten Zeichen um genau zu sein, in 2 Byte). Sobald der nun benutzt wird, wird diese automatisch zur Konvertierung herangezogen, wenn das erforderlich ist. Auf diese Weise kann man sich Binärdaten wunderbar kaputt machen.
Und auch an anderen Stellen greift die Compilermagic ein, so dass das ganze z.B. einfach mal langsamer ist als ein direkter Datenspeicher. Das merkt man natürlich erst bei größerem Datenaufkommen.
Und auch bei Indy passieren bei Strings Umwandlungen, die bei Datenbytes nicht passieren.
Wenn einem das so wichtig ist, dass man die Werte einfach so aneinanderhängen kann wie du geschrieben hast, dann kann man sich ja einen passenden Typ bauen, den man aber bei Binärdaten auch wirklich direkt damit füttert. Stringumwandlungen kann man ja auch anbieten, falls wirklich Stringdaten drin sind: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52:
| type TFoo = record Value: TBytes; class operator Add(const Value1, Value2: TFoo): TFoo; class operator implicit(const AValue: AnsiString): TFoo; class operator implicit(const AValue: TFoo): TBytes; class operator implicit(const AValue: TFoo): AnsiString; procedure LoadFromStream(const AStream: TStream; const ASize: Integer = -1); procedure SaveToStream(const AStream: TStream); end;
[...]
class operator TFoo.Add(const Value1, Value2: TFoo): TFoo; begin SetLength(Result.Value, Length(Value1.Value) + Length(Value2.Value)); CopyMemory(@Result.Value[0], @Value1.Value[0], Length(Value1.Value)); CopyMemory(@Result.Value[Length(Value1.Value)], @Value2.Value[0], Length(Value2.Value)); end;
class operator TFoo.implicit(const AValue: AnsiString): TFoo; begin SetLength(Result.Value, Length(AValue)); CopyMemory(@Result.Value[0], PByte(AValue), Length(AValue)); end;
class operator TFoo.implicit(const AValue: TFoo): TBytes; begin Result := AValue.Value; end;
class operator TFoo.implicit(const AValue: TFoo): AnsiString; begin SetLength(Result, Length(AValue.Value)); CopyMemory(PByte(Result), @AValue.Value[0], Length(AValue.Value)); end;
procedure TFoo.LoadFromStream(const AStream: TStream; const ASize: Integer = -1); var BytesAvail: Integer; begin BytesAvail := AStream.Size - AStream.Position; if (ASize >= 0) and (ASize <= BytesAvail) then BytesAvail := ASize; SetLength(Value, BytesAvail); AStream.Read(Value, BytesAvail); end;
procedure TFoo.SaveToStream(const AStream: TStream); begin AStream.Write(Value, Length(Value)); end; | Beispiel: Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| var a, b: TFoo; Test: TMemoryStream; begin a := 'test'; b := '12345'; ShowMessage(a + b); Test := TMemoryStream.Create; try a.SaveToStream(Test); Test.Position := 0; b.LoadFromStream(Test); ShowMessage(b); finally Test.Free; end; end; |
Für diesen Beitrag haben gedankt: Narses
|
|
Narses 
      

Beiträge: 10183
Erhaltene Danke: 1256
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: Do 12.07.12 18:16
Moin!
jaenicke hat folgendes geschrieben : | Solange man ausschließlich in einer bestimmten Codepage arbeitet, merkt man das vielleicht nicht
[...]
Auf diese Weise kann man sich Binärdaten wunderbar kaputt machen. |
Kannst du zum besseren Verständis dazu mal eben ein Beispiel zeigen? Und zwar konkret mit AnsiStrings!
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Do 12.07.12 20:53
Ein konkretes reales Beispiel habe ich dazu nicht mehr, weil ich es ja mittlerweile natürlich längst anders gelöst habe, aber den Effekt kann man schon mit diesen Zeilen sehr gut sehen (zumindest in aktuellen Delphiversionen): Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| var a: AnsiString; begin a := ' '; PByte(@a[1])^ := $D8; PWord(LongInt(a) - 12)^ := 1251; ShowMessage(a); PWord(LongInt(a) - 12)^ := 1252; ShowMessage(a); PWord(LongInt(a) - 12)^ := 1253; ShowMessage(a); |
Für diesen Beitrag haben gedankt: Narses
|
|
Narses 
      

Beiträge: 10183
Erhaltene Danke: 1256
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: Fr 13.07.12 10:37
Moin!
Danke für das Beispiel, so ähnlich hatte ich mir das gedacht. Um in diese Problematik reinzulaufen, müsste man schon zur Laufzeit die Codepage von bereits angelegten Strings wechseln.
Was mich und D7 angeht: damit betrachte ich Strings weiterhin als binary-save, da ich noch nie ein Programm gesehen habe, dass zur Laufzeit die Codepage eines bereits existierenden Strings ändert und ich mir auch keine Anwendung dazu denken kann. ja, ich weiß, dass das keine Garantie ist, dass das nicht doch möglich ist - aber nicht in meinen Programmen, denn genau das müsste ja der Entwickler selbst auch tun, sowas ändert sich nicht zur Laufzeit von selbst)
Aber gut zu wissen und nochmal danke für deinen Vorschlag für eine binäre Container-Klasse (wobei da noch einiges fehlt, um das wirklich produktiv nutzen zu können).
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Fr 13.07.12 12:13
Narses hat folgendes geschrieben : | Was mich und D7 angeht: damit betrachte ich Strings weiterhin als binary-save |
Da fehlt auch noch die ganze Compilermagic hinsichtlich der Umwandlung in UnicodeStrings, da das ohnehin kein bzw. schlecht Unicode kann. Deshalb sollte das da keine Probleme machen, richtig.
Narses hat folgendes geschrieben : | da ich noch nie ein Programm gesehen habe, dass zur Laufzeit die Codepage eines bereits existierenden Strings ändert und ich mir auch keine Anwendung dazu denken kann.  |
Wie schon geschrieben, ich habe die konkreten Daten und die Umgebungen nicht mehr zur Verfügung. Im realen Fall habe ich das nicht gemacht. Das diente hier nur dazu zu zeigen was das Ergebnis ist. Es handelte sich dabei um keine deutsche Windows-Umgebung, so dass ich das auch nicht so einfach erneut nachstellen kann. Es ging dort um aus einer seriellen Schnittstelle ausgelesene Daten. Das funktionierte bei mir auch problemlos, nur vor Ort leider nicht.
Das Entscheidende ist, dass immer MultiByteToWideChar benutzt wird um den AnsiString in einen UnicodeString umzuwandeln. Klar, wenn man jegliche Stringoperationen herauslässt (Copy, Pos, Konkatenierungen, ...) und so keine Konvertierungen durchgeführt werden, klappt es, weil die Umwandlung nie passiert. Aber dann sehe ich erst Recht keinen Sinn in der Verwendung von Strings.
// EDIT:
Narses hat folgendes geschrieben : | Was mich und D7 angeht: damit betrachte ich Strings weiterhin als binary-save, da ich noch nie ein Programm gesehen habe, dass zur Laufzeit die Codepage eines bereits existierenden Strings ändert |
Das ist insofern nützlich als ich mir dann die Behandlung sparen kann, weil die automatisch im Hintergrund passiert.
Für diesen Beitrag haben gedankt: Narses
|
|
Tranx
      
Beiträge: 648
Erhaltene Danke: 85
WIN 2000, WIN XP
D5 Prof
|
Verfasst: Fr 13.07.12 12:32
Also, für mich kommen Strings als Datenlager nicht in Frage, da ich eh Daten in sehr vielfältiger Form vorliegen habe, selten immer die gleiche Struktur. Aber eine Frage hätte ich doch an Narses:
Du schreibst, der Missbrauch von visuellen Komponenten als Datenlager sei eh schon außer Frage. Was meinst Du damit genau? Gilt das auch, wenn ich z.B. Daten in ein TMemo oder Stringgrid ablege? Was ist dagegen einzuwenden? Meist - wenn ich Daten ablege (sie liegen bei mir zumeist sowieso in Datenbanken) ist das dazu gedacht, diese Daten anderweitig zu verarbeiten (in Texten etc.) wieso sollte ich sie dann nicht vorher in solche Komponenten ablegen dürfen und anschließend abspeichern, um sie dann wieder im Text als Text einzubinden?
_________________ Toleranz ist eine Grundvoraussetzung für das Leben.
|
|
Narses 
      

Beiträge: 10183
Erhaltene Danke: 1256
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: Fr 13.07.12 12:50
Moin!
Tranx hat folgendes geschrieben : | Also, für mich kommen Strings als Datenlager nicht in Frage, da ich eh Daten in sehr vielfältiger Form vorliegen habe, selten immer die gleiche Struktur. |
Der Titel ist schon etwas seehr verallgemeinert, vielleicht sogar unpassend  (Ich glaub, ich pass das gleich auch nochmal an)
Ich dachte dabei z.B. ganz konkret an die Daten, die bei einer seriellen Kommunikation anfallen, die muss man ja irgendwo im Programm ablegen, egal wie oder wozu man sie verarbeitet. Strukturierte Daten legt man nicht in Strings ab, das ist klar.
Tranx hat folgendes geschrieben : | Du schreibst, der Missbrauch von visuellen Komponenten als Datenlager sei eh schon außer Frage. Was meinst Du damit genau? |
Klassisches Beispiel: Ein TMemo mit .Visible=FALSE statt einer TStringList zu nehmen. Das kann man Anfängern noch durchgehen lassen (und selbst das nicht ohne Hinweis), aber das sollte wohl grundsätzlich als Tabu betrachtet werden.
Tranx hat folgendes geschrieben : | Gilt das auch, wenn ich z.B. Daten in ein TMemo oder Stringgrid ablege? Was ist dagegen einzuwenden? |
Es ist dann was dagegen einzuwenden, wenn diese Daten dort intentional gespeichert sein sollen. Visuelle Komponenten zur Anzeige bzw. zum Bearbeiten zu verwenden, ist ja nicht zu vermeiden, wie sollte das sonst gehen.
Tranx hat folgendes geschrieben : | wenn ich Daten ablege (sie liegen bei mir zumeist sowieso in Datenbanken) |
Das ist genau das was ich meine, Daten gehören in ein dafür vorgesehenes "Datenlager" (z.B. Datenbank).
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
delfiphan
      
Beiträge: 2684
Erhaltene Danke: 32
|
Verfasst: Fr 13.07.12 17:40
Das zeigt auf der einen Seite auch, dass es eben praktisch ist, sich nicht um die Laufzeit der Objekte kümmern zu müssen...
Jedenfalls: Wenn du Rohdaten in einem String unterbringen willst, solltest du wenn schon auf RawByteString zurückgreifen. Da greift die Pseudo-CodePage $ffff, was vermutlich dann für Binärdaten geeignet ist.
Für diesen Beitrag haben gedankt: Narses
|
|
|