Entwickler-Ecke
Grafische Benutzeroberflächen (VCL & FireMonkey) - Streamdaten lesen/verarbeiten
hRb - Mi 26.07.17 00:02
Titel: Streamdaten lesen/verarbeiten
Hallo,
Ich stelle ein funktionsfähiges D7-Programm (Ansi-String) auf XE3 um. Überwiegend sind Datenbankexporte in csv-Format zu verarbeiten. Die folgende "schulmäßige" Methode funktioniert nicht mehr, nämlich das Einlesen von ANSI-Daten .
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| var fStream:string; ch :char; if Execute then with TFileStream.Create(FileName,fmShareDenyNone) do if FindFirst(FileName, faAnyFile, SearchRec)=0 then begin len:=SearchRec.Size; FindClose(SearchRec); SetLength(fStream,len); Read(fStream[1],len); ... fStream wird nun Byteweise analysiert, u.a. nach Trennzeichen und evtl. Hochkomma. Dann zeilenweise verarbeitet. Zugriff mit ch:=fStream[i]; |
Unter XE3 gibt es mehrere Fehler:
1. nach obiger Befehlsfolge stehen in fStream keine ANSI-Zeichen, sondern chinesische Hyroglyphen
hier Anlage ansehen (jpg-Bild) (kann leider kein Bild einfügen)
2. definiere ich um
var fStream:TStream;
so lässt sich das Programm nicht mehr compilieren. Folgender Befehl führt zum Fehler
Compilermeldung: [dcc32 Fehler] Unit1.pas(2108): E2149 Klasse besitzt keine Standardeigenschaft
Frage1: warum steht in fStream kein Ascii-Text
Frage2: wie greife ich auf Stream-Daten zeichenweise zu
Wer kann helfen?
Holgerx - Mi 26.07.17 10:16
Hmm..
D7 : String = AnsiString = 1 Byte je Char
XE : String = UniCode = min. 2 Byte je Char
(Quick and Dirty)
Gehe in deiner Routine hin und ersetze das
var fStream:string;
durch
var fStream:AnsiString;
;)
Ein Stream arbeitet immer Byte-Basierend und nicht Char-Basierend.
Deshalb klappt das hier nicht mit UniCode..
Hinweis:
Das funktioniert nur, wenn die CSV-Datei ANSI/ASCII codiert ist und nicht UniCode ;)
jfheins - Mi 26.07.17 22:14
Bitte denke dran, dass du mit fStream[i] immer genau eine CodeUnit bekommst, die 1-2 Codepoints beschreibt. Das ist nicht wirklich hilfreich.
Lösung: Zugriff auf den Indexer eines Strings möglichst vermeiden.
Du könntest die komplette Datei in einen String einlesen (Encoding angeben!) und danach na den Semikolons splitten.
In neueren Delphis gibt es dafür offenbar schon eine Funktion:
Delphi-Quelltext
1:
| function ReadAllText(const Path: string; const Encoding: TEncoding): string; |
Solange deine Datei nicht größer wird als 500MB sollte das passen. (Wenn doch, wird es knapp mit dem 1GB String im Speicher)
hRb - Mi 26.07.17 23:11
Hallo, liebe Helfer,
ich verstehe die hilfreichen Tipps nur teilweise.
1. Ich stelle das Programm ja gerade von AnsiString auf String um, damit mögliche Sonderzeichen verarbeitet werden können.
2. Der Typ String bei XE ist m.W. ja UTF8-Zeichensatz und belegt nur dann 2 Byte, wenn die Zeichen den Ascii-zeichenraum 0..128 überschreiten (darunter nur 1 Byte).
3. Mit der Anweisung
lese ich ja genau die Länge der Datei in Byte und mit
Read(fStream[1],len);
exakt die Datei ein.
Nun liegt es doch an meiner Verarbeitung festzustellen ob ein Zeichen zwei Byte belegt. Demzufolge sollte ich auch auf jedes einzelne Byte im String zugreifen können. Oder liege ich da falsch? bzw. wozu ist dann die Read-Methode in XE-Compilern noch da?
Hinweis: Ich habe im Programm auch den Opendialog mit
Delphi-Quelltext
1:
| Lines.LoadFromFile(DateiName); |
Da werden die Zeichen korrekt dargestellt. Da jedoch bei csv-ExportDaten die Werte oft mit " .. " gepackt werden und innerhalb dieser Zeichenfolge #10 oder #13 als Umbruch vorkommen können, habe ich bisher die Read-Methode verwendet.
Keinen Hinweis gab es, warum der Compiler den Befehl ch:=fStream[i] unter XE nicht übersetzt
Holgerx - Do 27.07.17 05:47
Hmm..
hRb hat folgendes geschrieben : |
2. Der Typ String bei XE ist m.W. ja UTF8-Zeichensatz und belegt nur dann 2 Byte, wenn die Zeichen den Ascii-zeichenraum 0..128 überschreiten (darunter nur 1 Byte).
|
Wie kommst Du denn darauf?
UniCode ist immer 2 Bytes je Char (bestimmte Codepages ziehen 2 UniCode Chars zu einer CodeUnit zusammen) und sollte in XE ein UTF-16 sein!
hRb hat folgendes geschrieben : |
3. Mit der Anweisung
lese ich ja genau die Länge der Datei in Byte und mit
Read(fStream[1],len);
exakt die Datei ein.
Nun liegt es doch an meiner Verarbeitung festzustellen ob ein Zeichen zwei Byte belegt. Demzufolge sollte ich auch auf jedes einzelne Byte im String zugreifen können. Oder liege ich da falsch? bzw. wozu ist dann die Read-Methode in XE-Compilern noch da?
|
Richtig! Du liest BYTES ein, keine Chars!
Wenn deine Datei Ansicodiert ist, dann stehen da immer 1 Byte = 1 Char drinnen.
Wenn Du nun diese Bytes (und was anderes list du mit Read nicht ein) in einen Unicode String einliest, dann werden somit 2 Bytes (= 2 AnsiChars) in ein Unicode Char gelesen. Das passiert auch im Windows-Editor, wenn dieser Chinesische Zeichen anzeigt ;)
Wenn Du mit String Index arbeiten möchtest, musst Du vorher prüfen (Stichwort BOM) ob es eine Ansi oder Unicode Datei ist und dann entsprechend in ein Ansistring oder Unicodestring einlesen!
Sprich bei ASCII/ANSI-Dateien mit AnsiString einlesen und bei Unicode-Dateien mit string (= UnicodeString unter XE).
Mit deinem FStream[x] greifst Du nicht auf das x-te BYTE sondern auf das x-te CHAR zu. somit bei Ansistring immer auf das Byte, bei UniCode immer auf 2/4 Bytes!
Somit ist die Methode nicht wirklich brauchbar zum 'nachträglichen' aufdröseln..
hRb - Do 03.08.17 21:50
Zitat: |
Wie kommst Du denn darauf? |
Ok, da muss ich wohl umdenken. Glaubte gelesen zu haben, dass der Aufruf LoadFromFile ein encoding vornimmt und in UTF8 codiert. Zumindest glaube ich dies bei txt- csv- oder pas-Dateien zu erkennen. (Hätte bei ReadStream ja auch sein können)
Zitat: |
UniCode ist immer 2 Bytes je Char |
Das ist klar, mir ging es um UTF8-Code
Zitat: |
bestimmte Codepages ziehen 2 UniCode Chars zu einer CodeUnit zusammen |
heißt das ein Byte? z.B. bei Ascii-Zeichen? Wenn Ja, welche Codepages tun dies bzw. kann ich als Programmierer die Codepage festlegen / wie?
Eines jedenfalls wird für mich klar: so einfach -wie oft beschrieben- stellt man Ansi-String-Programme nicht auf den allgemeinen String-Typ um.
PS: mit der encoding-Function laboriere ich gerade und sammle Erfahrungen
Gruß hRb
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2024 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!