AnsiString speichern und laden
Hallo,
ich will einen AnsiString speichern und wieder öffnen. Habe ein Tutorium von Himitsu zum Thema gefunden. Bevor ich das gefunden hatte, wollte ich es so machen:
Delphi-Quellcode:
Um Kompatibilität mit alten Delphi-Versionen geht es mir nicht. Geht das so in Ordnung?
public
Txt: AnsiString; Txtarray: TArray<Byte>; Path: TFilename; procedure TForm1.Button2Click(Sender: TObject); var i: Integer; begin if Txt = '' then Exit; SetLength(Txtarray,Length(Txt)); for i:=1 to Length(Txt) do Txtarray[i-1] := Ord(Txt[i]); TFile.WriteAllBytes(Path,Txtarray); end; procedure TForm1.Button3Click(Sender: TObject); var i: Integer; begin TxtArray := TFile.ReadAllBytes(Path); Txt := ''; for i:=0 to Length(Txtarray) do Txt := Txt + Chr(Txtarray[i]); Memo1.Text := Txt; end; Gruß Willie. |
AW: AnsiString speichern und laden
Leider verstehe ich nicht so ganz was du da genau machen willst. Wieso so kompliziert? Wieso nicht mit einer TStringList und SafeToFile? Warum willst du das überhaupt als ANSI speichern?
Delphi-Quellcode:
with TStringList.Create do
try { Speichern } Text := String(DeinAnsiText); SaveToFile(DeinFileName, TEncoding.ANSI); { Laden } LoadFromFile(DeinFieleName, TEncoding.ANSI); DeinAnsiText := AnsiString(Text); finally Free end; |
AW: AnsiString speichern und laden
Da Byte und AnsiChar gleich groß sind, kann man statt der Schleife und jedem Char einzeln auch einmal Move oder SetString verwenden.
Statt den direkten Casts (siehe Rolf Frei) kann man auch TEncoding verwenden. (die Casts sind hier aber einfacher) Und wenn du schon TFile.WriteAllBytes verwendest ... dir ist aufgefallen, dass es da auch Methoden für Text/String gibt? Und TStringStream gibt es auch noch. (das uralte AssignFile+Write hat noch ein AnsiString als Input) Viele Standardfunktionen gehen nutzen halt String und es gibt sie nicht mit AnsiString, darum ist geht hier dann oft der Umweg über einen String (UnicodeString). |
AW: AnsiString speichern und laden
Moin...8-)
Delphi-Quellcode:
...mich gruselts. :twisted:
with TStringList.Create do
. [Gebetsmühle on] with nicht mehr verwenden! ... Probleme z.B. mit TRect und keine Auflösung der Variablen im Debugging! :warn: [Gebetsmühle off] |
AW: AnsiString speichern und laden
Gegen with ist in so einem regional beschränkten einfachen Fall nichts einzuwenden, vorallem weil darin nur mit Sachen des erstellten Objects gearbeitet wird. Die Frage ist immer wo und für was man es einsetzt. Hier mit dem try/finaly und einer TStringList passt das problemlos, aber das ist ein anderes Thema, das nichts mit der Originalfrage zu tun hat.
|
AW: AnsiString speichern und laden
Du hast schon recht, momentan kann da nix schiefgehen. Interessant wird es erst wenn die Sache komplexer wird und man vergisst den Unsinn zu entfernen.
|
AW: AnsiString speichern und laden
Hallo,
danke für eure Tipps, ich habe lange ein altes Delphi benutzt, darum kenne ich noch nicht alle Verbesserungen. Warum AnsiString statt WideString? Ich hatte mir vor vielen Jahren eine einfache Verschlüsselung ausgedacht. Ich verknüpfe das 2. Nibble des 1. Bytes mit dem 1. Nibble des 2. Bytes usw. und zum Schluss noch das erste mit dem letzten Nibble. Nur als Teil der Verschlüsselung! Mit WideStrings macht das keinen Sinn. Ich will auf keinen Fall jetzt eine Diskussion über Verschlüsselung anfachen! Das war nur eine Idee, die ich damals hatte und will sie mal ausprobieren. Willie. PS. with TFenster.Create do try Showmodal finally Free end benutze ich oft und sehe darin kein Problem, es spart Quelltext und ist übersichtlich. |
AW: AnsiString speichern und laden
Idee, verpack doch dein AnsiString in ein Base64 Encoding string.
Dann brauchst Du Dir um Unicode nicht mehr viele Gedanken machen. Nur noch die eigene Lade/Speicher methode mit dem Base64 ergänzen, fertig. (Es kann auch jede andere Base64 Lösung genommen werden, die ist halt bereits enthalten.) Viel Erfolg! |
AW: AnsiString speichern und laden
Also hast du keinen AnsiString (CP_ACP) sondern einen RawByteString, oder besser noch ein TBytes.
Und vorallem mit Letzterem bereitet das TFile.WriteAllBytes keine Probleme. |
AW: AnsiString speichern und laden
Zitat:
|
AW: AnsiString speichern und laden
Inzwischen gibt es ja nun die Inline-Variablen.
Delphi-Quellcode:
var F := TMyForm.Create(nil);
try finally F.Free; end; |
AW: AnsiString speichern und laden
Zitat:
KodeZwerge, damit muss ich mich beschäftigen. Willie. |
AW: AnsiString speichern und laden
Du kannst da eifnach eine Typecast auf AnsiString machen:
Delphi-Quellcode:
Du musst da aber aufpassen, denn wenn dein Memo Unicodezeichen enthält, die es im ANSI nicht gibt, wirst du da an der Stelle ein "?" haben. Da musst dir gründlich überlegen, ob du das da nicht anderst machen willst, damit keine Konvertierung Unicode/ANSI stattfinden muss.
var
MeinAnsiStr: AnsiString; MeineBytes: TBytes; begin MeinAnsiStr := AnsiString(Memo1.Lines.Text); // Kann zu Zeichenverlust führen, wenn ein Zeichen nicht im ANSI untersützt wird! MeineBytes := BytesOf(MeinAnsiStr); ... end; Du könntest ja auch einfach alles als Unicode nutzen und verschlüsseln.
Delphi-Quellcode:
In diesem Fall hast du ein ByteArray aus Unicodezeichen, also in der Regel sowas wie 40 00 45 00... Das könnte ja deine Routine auch auf Bytebene (wie bisher AnsiChar) vershlüsseln. StringOf(MeineBytes) macht dann übrigens das Gegenteil, also aus TBytes wieder ein String.
MeineBytes := BytesOf(Memo1.Lines.Text);
|
AW: AnsiString speichern und laden
Zitat:
Beim AnsiString (CP_ACP) ist vorallem besonders spaßig, dass bei unterschiedlichen Sprachen auch andere Zeichen codiert sind. z.B. AnsiString-zu-String liefert ein anderes Ergebnis in Deutschland, Russland, China usw. Ja, String/Char ist seit Delphi-2009 Unicode, genauer UnicodeString/WideChar mit 2 Byte pro Char. Der WideString ist bissl was Anderes, hat aber die gleichen Chars drin. TEncoding Delphi macht es ähnlich, beim Cast mit Unicode von/zu ANSI. Ein AnsiString und seine Nachfahren haben seit 2009 eine CodePage. AnsiString = CP_ACP / 0 UTF8String = CP_UTF8 / 65001 RawByteString = $FFFF Auch UnicodeString hat quasi eine CodePage 1200 https://stackoverflow.com/questions/...01-12000-12001 https://www.delphipraxis.net/206950-...ml#post1482784 |
AW: AnsiString speichern und laden
Da habe ich einiges zu lesen (bzw. vorlesen zu lassen) !
In europäischen Sprachen wird doch das zweite Byte nicht gebraucht, richtig? Willie. |
AW: AnsiString speichern und laden
ä ö ü ß
oder z.B. bei den Franzosen und Dergleichen auch é ê ë ì í î ï ñ ò ó ô õ ö ... , was nicht alles in die 255 rein passt. |
AW: AnsiString speichern und laden
Doch da gibt es auch solche Zeichen. Z.B. das Euro Zeichen hat den Wert $20AC.
Hier gibt es ein White Paper von Emba zu Unicode mit Delphi und was man da für die Migration beachten muss: White Paper: Delphi and Unicode Oder das hier: Delphi Unicode Migration for Mere Mortals Lies dir diese PDF's mal durch und dann wird schon vieles viel einfacher verständlich sein. Es gibt übrigens bei Embarcadero einen eigenen Bereich für die Migration, wo auch auf das Thema Unicode Migration eingegangen wird. Hier findest du die Seite und weitere Links zum Thema: https://www.embarcadero.com/rad-in-a...upgrade-center |
AW: AnsiString speichern und laden
Willie möchte aber nicht aus Ansicode Unicode machen, er hat lediglich den falschen Datentyp für sein Experiment genutzt.
TBytes nennt es sich heute, damals halt
Delphi-Quellcode:
.
array of byte
Ich kenne die Problematik, da auch ich mich mal fürs falsche Entschieden hatte. Eine sofort Korrektur mit minimal Aufwand wäre halt per Base64 möglich. Encode(AnsiString) / Decode(Base64String) o.ä.. Jedenfalls hatte ich mich damals dafür Entschieden und würde es wahrscheinlich wieder machen ;-] Ebenfalls möglich ohne viel Aufwand auf einen TStream umzusatteln. Das ganze total Oldskool als Record laden/speichern ginge auch. Da muss halt im Record der Typ stimmen. Also es gibt viele Möglichkeiten so das Dein En-/Kodierverfahren weiterhin genutzt werden kann, nur außen rum brauchst Du halt was anderes. |
AW: AnsiString speichern und laden
Viele gute Antworten. Danke.
Aber ich schaffe es nicht, die Nibbles so zu verknüpfen, wie ich mir das vorgestellt habe. Ich erkenne nicht, ob der Fehler am Codieren oder Decodieren liegt. Ich habe die Bereichsprüfung eingeschaltet, um einen Überlauf zu erkennen. Ist aber nicht. Willie. |
AW: AnsiString speichern und laden
Es gibt verschiedene Einstellungen für TEncoding bzw. WideCharToMultiByte und standardmäßig gibt es keine Fehlermeldung, wenn es nicht passt.
https://www.delphipraxis.net/207225-...evexpress.html Und die Bereichsprüfung kann hier nicht greifen, dass die Chars nicht einzeln im Delphi-Code von WideChar ins AnsiChar zugewiesen werden. Bestes Beispiel: UTF8Decode und seine Freunde geben einfach still und heimlich einen Leerstring zurück, wenn man man dort "ungültiges" UTF-8 reingibt. Und standardmäßig werden eben ungültige unpassende WideChars in ein '?' übersetzt, wenn es nicht passt. (bei den AutoCatst still und heimlich, da Rückgaben nicht geprüft werden) Außerdem kann es sein, dass Combining-Chars zusammengefasst werden, aber zurück dann nicht wieder getrennt. Oder A mit Akzent wird in ein pures A übersetzt und zurück geht dann nicht mehr. Aber hier kann man mit den passenden Optionen und Auswertung des Rückgabewertes entgegengewirkt werden. |
AW: AnsiString speichern und laden
Ich weis nicht, ob ich dir damit helfe, wenn ich mORMot ins Spiel bringe. Der Thread ist aber schon etwas länger und die Unit SynCommons enthält viele nützliche Funktionen für den Programmiereralltag. mORMot ist von D7 bis 10.4 verfügbar. Muss nicht installiert werden, es reicht, die Bibliothekspfade zu setzen. Den Download findest du hier. Es steht eine ausführliche Hilfe, viele Beispiele und ein freundliches Forum zur Verfügung.
Umgesetzt im Anfangsbeispiel:
Delphi-Quellcode:
Disclaimer: Ich weis schon, Kanonen auf Spatzen ... mORMot ist bei mir inzwischen in jedem Projekt und im Alltag inzwischen eine unverzichtbare Allzweckwaffe.
uses
SynCommons; procedure TForm1.Button2Click(Sender: TObject); begin if Txt = '' then Exit; SynCommons.FileFromString(Txt, Path); end; procedure TForm1.Button3Click(Sender: TObject); begin Txt := SynCommons.StringFromFile(Path); Memo1.Text := UTF8ToString(Txt); end; Bis bald... Thomas |
AW: AnsiString speichern und laden
Binärdaten in Strings waren noch nie eine super Idee.
Alternativen gibt es zu Genüge und wurden Einige genannt. |
AW: AnsiString speichern und laden
@Willie1: Auch wenn du es nicht hören wolltest, Kryptografie ist mit den richtigen Units vernünftig umzusetzen. Nimm besser die folgenden Funktionen:
Delphi-Quellcode:
Anwenden kannst du das wie folgt:
uses
SynCommons, SynCrypto, SynZip; const KEY_FILE_HEADER = 'TOPSECRET'; KEY_FILE_HEADER_SIZE = Length(KEY_FILE_HEADER); function SaveToFile(const pmcRaw, pmcPassword: RawByteString; const pmcFileName: TFileName): Boolean; begin Result := False; if (pmcRaw <> '') and (pmcPassword <> '') and (DirectoryExists(ExtractFilePath(pmcFileName))) then begin Result := FileFromString(KEY_FILE_HEADER + SynCrypto.AESSHA256(SynZip.CompressString(pmcRaw), pmcPassword, True), pmcFileName); end; end; function LoadFromFile(const pmcFileName: TFileName; const pmcPassword: RawByteString; out pmcRaw: RawByteString): Boolean; var sSrc, sOut: RawByteString; begin Result := False; if (pmcPassword <> '') and FileExists(pmcFileName) then begin sSrc := StringFromFile(pmcFileName); if (sSrc <> '') and (PosEx(KEY_FILE_HEADER, sSrc, 1) = 1) then begin SetString(sOut, Nil, Length(sSrc) - KEY_FILE_HEADER_SIZE); SynCrypto.AESSHA256(PAnsiChar(sSrc) + KEY_FILE_HEADER_SIZE, Pointer(sOut), Length(sOut), pmcPassword, False); pmcRaw := SynZip.UnCompressString(sOut); Result := (pmcRaw <> ''); end; end; end;
Delphi-Quellcode:
Bis bald...
procedure TForm1.btnSaveClick(Sender: TObject);
begin if SaveToFile(StringToUTF8(memoTopSecret.Text), 'Willie1', ChangeFileExt(ParamStr(0), '.key')) then memoTopSecret.Clear; end; procedure TForm1.btnLoadClick(Sender: TObject); var secStr: RawByteString; begin if LoadFromFile(ChangeFileExt(ParamStr(0), '.key'), 'Willie1', secStr) then memoTopSecret.Text := UTF8ToString(secStr); end; Thomas |
AW: AnsiString speichern und laden
Damit er erstmal dennoch weiterkommt
ohne extras die delphi nicht besitzt für das Experiment habe ich mal was getippst hier in Editor, in der Hoffnung das wichtigste zu zeigen.
Delphi-Quellcode:
nicht getestet, nur getippt
uses System.NetEncoding, System.IniFiles;
function WilliEnc(const AValue: AnsiString): AnsiString; var Nibble: AnsiString; begin Nibble := AValue; // mach hier dein nibble ding // hier verpacken wir alles in ein Base64 Nibble := TNetEncoding.Base64.Encode(Nibble); Exit(Nibble); end; function WilliDec(const AValue: AnsiString): AnsiString; var Bytes: TBytes; Nibble: AnsiString; begin // hier wird aus dem base64 wieder ein ansistring, und zwar nur ein ansistring (!) Bytes := TNetEncoding.Base64.DecodeStringToBytes(AValue); Nibble := TEncoding.ANSI.GetString(Bytes); // ab dieser stelle ist der geladene base64 kodierte inhalt wieder dein original ansistring // also mach ab hier dein nibble ding :-) Exit(Nibble); end; function LoadData: string; var Ini: TIniFile; begin Result := ''; if FileExists('name.ini') then begin Ini := TIniFile.Create('name.ini'); try Result := WilliDec(Ini.ReadString('Sektion', 'Ident', '')); finally Ini.Free; end; end; end; procedure SaveData(const AValue: string); var Ini: TIniFile; begin Ini := TIniFile.Create('name.ini'); try Ini.WriteString('Sektion', 'Ident', WilliEnc(AValue)); finally Ini.Free; end; end; // exemplarische Anwendung procedure TForm1.btnLoadClick(Sender: TObject); begin Edit1.Text := LoadData; end; procedure TForm1.btnSaveClick(Sender: TObject); begin SaveData(Edit1.Text); end; ...roter text beim speichern oh oh... //edit an Thomas: ich bin voll auf deiner seite! |
AW: AnsiString speichern und laden
Hallo,
da brauche ich Zeit, um das alles bewerten zu können. Mit der Kryptographie stimmt natürlich, es gibt eine komplette AES-Verschlüsselung als Delphi-Unit von einem Uni-Mathematiker aus Kiel, muss mal sehen, ob ich das noch wiederfinde. Mein Ansatz hat ja Fehler: zB. das Zeichen #255 und eine Zeichenkette = Linie wie ---- usw. würde es sofort offenbaren. Ich werde eure Erklärung ernst nehmen und "nachdenken". Willie. |
AW: AnsiString speichern und laden
Zitat:
wie Du bemerkst wollen Dir ja viele helfen, mein Vorschlag, öffne einen neuen Thread so das wir da uns mit Kryptographie beschäftigen können. Es gibt tausende Möglichkeiten wie man etwas verschlüsseln könnte. Enorm viel geht schon mit Delphi Bordmitteln, oft läuft es auf ein XOR hinaus. Bitmanipulation muss natürlich sehr durchdacht sein. Aber das wichtigste ist halt alles auf den richtigen Datentyp abzustimmen. Nur nicht Kopf in den Sand stecken, zusammen packen wir das schon :-) |
AW: AnsiString speichern und laden
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:27 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