![]() |
TTextStream - Textdateien einlesen
Liste der Anhänge anzeigen (Anzahl: 8)
So, den nun hab ich erstmal den Schreib-/Lesekern meiner neuen StringListe seppariert und er läuft endlich.
Manchmal muß man eben mit mehrfachem Code leben ... hartkodierte Konstanten sind eben schneller, als Variablen und eine dynamische Verarbeitung. Diese Klasse ließt eine beliebig große Textdatei sequentiell ein, wobei sogar unterschiedliche Kodierungen (TEncoding) unterstützt werden und ein eventuelles BOM ausgewertet wird. Speichern ist natürlich auch möglich. Nja, die Speicherverwaltung des Lesepuffers gefällt mir noch nicht so ganz ( ![]() aber für diesen Fall dürfte es denoch ausreichend sein. Ja nach Datei und Computer ist es etwa gleichschnell oder schneller als eine TStringList zu Einlesen braucht (wobei die TStringList irgendwann an ihre Speichergrenzen stößt, da sie alles im Arbeitsspeicher verarbeitet, welches beim Einlesen einer einfachen Ansi-Datei in Delphi2009/2010 mehr als den 4-fachen Speicherbearf, der ursprünglichen Dateigröße verlangt) Als Zusatzmodul ist mir eingefallen, daß man die (ur)alten Pascal-Datei-Funktionen ersetzen könnte, aber leider ist es nicht möglich einen adequaten Ersatz für Read, ReadLn, Write und WriteLn zu finden :cry:, Aber vielleicht hat ja jemand eine brillante Erleuchtung. PS: Der Name "TStringStreamEx" der Klasse gefällt mir eigentlich auch nicht, aber irgendwer hatte schon die Idee eine andere Klasse TStringStream zu nennen. :? [edit] Name angenommen :stupid: [edit 20.05.2010]
[edit 21.05.2010 v1.2c] Wo es nun zu laufen scheint, hab ich mir mal die Unterschiede angesehn und beide Versionen miteinander kombiniert. Außerdem hatte ich glatt was vergessen zu übernehmen. :shock: Beim Einlesen einer Datei werden die Zeilenumbrüche analysiert und das Property LineBreak enthält dann den häufigsten Zeilenumbruch (falls es mal ein bissl gemischt ist) ... die FileStringList wird somit später den Zeilenumbruch einer Datei quasi erhalten und ihn nicht ständig auf Windowsstandard (CRLF) abändern. :-D [edit 17.08.2010 v1.3] - BOM-Erkennung bei Angabe einer Kodierung integriert - BOM kann nun beim Schreiben weggelassen werden [edit 18.10.2010 v1.4a2] - neue Testversion (sie Beitrag #31) |
Re: TStringStreamEx - Textdateien einlesen
Nur kurz zur Namensgebung:
Zitat:
[edit]BBCode gefixt[/edit] |
Re: TStringStreamEx - Textdateien einlesen
Hallo himitsu,
nette Klasse hast du da erstellt. Wollte sie mal ausprobieren aber mir fehlen leider folgende Typen: TEncoding, TBytes, TMBCSEncoding Habe die Classes, SysUtils bereits eigebunden ... aber keine Unit für die oberen Typen gefunden. (Sind die vielleicht von dir?) Danke gsh |
Re: TStringStreamEx - Textdateien einlesen
Das ist vermutlich wieder alles Unicode-Gedöns (zumindest TEncoding), also erst ab D2009 zu gebrauchen.
|
Re: TStringStreamEx - Textdateien einlesen
@DeddyH
Noar, also ab Delphi 2009 ... aber man könnte sich notfalls auch einen Dummy für TEncoding erstellen und dann dürfte es auch in älteren Delphis laufen. TEncoding hatte ich eben genommen, da es "aktuell" auch in der VCL verwendet wird und somit leichter benutzbar ist , außerdem befindet sich somit kein Code für eine En-/Decodierung im eigenen Projekt und es kann alles extern verarbeitet werden. TBytes ist einfach nur ein Array of Byte. [add] Ich mach jetzt nur noch schnell was Anderes fertig und dann versuch ich es mal in TDE zum Laufen zu bekommen. |
Re: TStringStreamEx - Textdateien einlesen
Zitat:
für ein Read (bei "Text - Dateien") sehe ich eigentlich keine Verwendung (wer braucht schon ein Read(char)). Beim Readln kommt man um das scannen nach dem EOL nicht herum, dafür kann man dann auch frei definieren wodurch EOL gekennzeichnet ist (CRLF, LFCR, CR, LF, #0.....) Und man baut noch gleich einen Interpreter für die alten ANSI-Codes mit ein (!?) Und das alles natürlich frei definierbar...... Ach ja bei der Gelegenheit kann man gleich noch BigEndian und LittleEndian berücksichtigen...... ;-)) Gruß K-H |
Re: TStringStreamEx - Textdateien einlesen
Zitat:
WriteLn(123, i, 'ads', s) kann man ja notfalls durch WriteLn([...]) ersetzen. Zitat:
und der "Parser" sollte sowas auch beachten. :angel: So, ein Art kombiniertes Write/WriteLn gibt es, aber natülich nicht das Read/ReadLn. Read ließt nur einen Wert, der aktuellen Zeile und EoLn gibt an, ob es noch weitere Werte in der aktuellen Zeile gibt. (praktisch fast genauso, wie bei den alten Pascalfunktionen) Diese Textzeile
Code:
könnte man also folgendermaßen auslesen
132 abc true
Delphi-Quellcode:
oder 'ne ganze Datei gleich mal so ... Wert für Wert:
F.Read(int);
F.Read(str); F.Read(bool);
Delphi-Quellcode:
Ja, und ich hoffe mal die Vor2009-Variante läuft gut.
F := TTextStreamEx.Create('Datei.txt', saRead);
Try While not EoF do Begin While not EoLn do ShowMessage(ReadString); ReadLn; End; Finally F.Free; End; Als Bonus hat sie eine einfache Variante des TEncoding bekommen, welches man natürlich auch für andere Dinge nutzen könnte. |
Re: TStringStreamEx - Textdateien einlesen
Zitat:
Gleich mal als erstes: Zeile 259 steht einfach das Wort CompilerVersion ... was da sicher nicht hingehört und ws ein "Strg+V Fehler" ist :zwinker: Dann wollte ich noch sagen das ich unter D2006 folgende Hinweise und Warnungen erhalte: Zitat:
|
Re: TStringStreamEx - Textdateien einlesen
Zitat:
Zitat:
Ansonsten hoff' ich mal, daß die anderen Meldungen nun weg sind. Zitat:
(also String und PChar unverändert ... im restlichen Code mußte es aber nach WideString geändert werden) Zitat:
|
Re: TStringStreamEx - Textdateien einlesen
Zitat:
(die Großrechner-Schädigung kommt eben immer wieder durch) und bevor es jemand anmerkt, die Konsole hab ich immer mit
Delphi-Quellcode:
bedient. Ein schnödes
repeat until keypressed; read(inkey)
Delphi-Quellcode:
ist mir sehr selten über den Weg gelaufen.
readln(konsolendaten)
Gruß K-H |
Re: TStringStreamEx - Textdateien einlesen
Zitat:
Manchmal sind die alten Pascal-Funktionen eigentlich recht praktisch. Nur schade ist, daß man damit nur ANSI-Text-Dateien erstellen und auslesen kann und das interne Caching ist nicht unbedingt .... nja, ich wie soll man es denn nennen? ... optimal? Hiermit könnte man sogar eine normale TStringList effektiver füllen. Zumindestens was größere Dateien angeht, dann so ab einer 300 MB-Textdatei bekommt man schonmal ein OutOfMemory, da ja alles am Stück eingelesen und verarbeite wird, also wärend des LoadFrom... und SaveTo.... |
Re: TTextStream - Textdateien einlesen
[info] nicht wundern ... es gibt jetzt nur noch eine Version für Unicode (D2009/2010) und die anderen Delphis.
Nja, und ein paar vergessene Codezeilen wurden noch schnell integriert ... die Erkennung der Zeilenumbrüche (siehe [edit] in #1). |
Re: TTextStream - Textdateien einlesen
Fein gemacht! :thumb:
Ein Verbesserungsvorschlag für Zeile 707:
Delphi-Quellcode:
Ohne dem dem fmCreate machts bei neuen Dateien einfach nur buuuuuuum. ;)
Else Mode := fmOpenReadWrite or fmShareDenyWrite or fmCreate;
|
Re: TTextStream - Textdateien einlesen
Ups, also für Zeile 706+707 dann Dieses:
Delphi-Quellcode:
Im Testcode lese ich über einen Stream ein und schreibe auch darüber. Und dort wird über CreateFile + einen speziellen THandleStream gearbeitet ... da ist dieser CodeTeil wohl etwas zukurzgeraten, beim Test. :oops:
If Access = saRead Then Mode := fmOpenRead or fmShareDenyWrite
Else If Access = saAppend Then Mode := fmOpenReadWrite or fmShareDenyWrite Else Mode := fmCreate or fmOpenReadWrite or fmShareDenyWrite; Hier knallt's nicht, aber es ist schon blöd, daß man dem TFileStream nicht weitere Attribute mitgeben kann :cry: (vorallem FILE_FLAG_RANDOM_ACCESS und FILE_FLAG_SEQUENTIAL_SCAN geb ich ja gerne mal an, um Windows ein bissl unter die Arme zu greifen)
Delphi-Quellcode:
Mal sehn, vielleich verbau ich noch 'ne Abwandlung davon in diesem Code. :gruebel:
Case Mode of
fmReadWrite: Begin A := GENERIC_READ or GENERIC_WRITE; C := OPEN_EXISTING; End; fmCreate: Begin A := GENERIC_READ or GENERIC_WRITE; C := CREATE_NEW; Mode := fmReadWrite; End; fmCreateOrRW: Begin A := GENERIC_READ or GENERIC_WRITE; C := OPEN_ALWAYS; Mode := fmReadWrite; End; Else Begin A := GENERIC_READ; C := OPEN_EXISTING; End; End; H := CreateFile(PChar(Filename), A, FILE_SHARE_READ, nil, C, FILE_FLAG_RANDOM_ACCESS or FILE_ATTRIBUTE_NOT_CONTENT_INDEXED, 0); If H = INVALID_HANDLE_VALUE Then Raise EFCreateError.CreateResFmt(@SFCreateErrorEx, [ExpandFileName(Filename), SysErrorMessage(GetLastError)]); AssignToStream(THandleStream2.Create(H), True, Mode = fmReadOnly, Encoding); |
Re: TTextStream - Textdateien einlesen
Dann habe ich noch ein Problem ... beim Flush im Destructor eines schreibenden (logisch :) ) TTextStreams kommt eine Zugriffverletzung an der Stelle
Delphi-Quellcode:
in der Funktion "WideCharToMultiByte".
FByteBuffer := FEncoding.GetBytes(FStringBuffer);
Ich gebe zu, dafür kannst du wahrscheinlich nicht direkt was, aber falls dir eine Lösung einfällt, würde ich mich freuen. :) Das hier funktioniert nicht:
Delphi-Quellcode:
Das gleiche in einer ConsolenApp geht [edit]auch nicht[/edit]. :wall:
procedure TForm30.FormCreate(Sender: TObject);
var tt : TTextStream; begin tt := TTextStream.Create('f:\test.txt', saWrite); tt.WriteLine(DateTimeToStr(Now)); tt.Free; end; |
Re: TTextStream - Textdateien einlesen
Oh, da hat sich noch ein Fehler bei der Pufferumstellung eingeschlichen
(früher Byte-Array mit 0-Index und jetzt String mit der bösen 1, aber die anderen Codestellen sehen diesbezüglich OK aus :angel2: ) Zeile 811
Code:
und Zeile 836
[b]Procedure[/b] TTextStream.WritePart(Const S: SString);
[b]Begin[/b] ... Move(S[1], FStringBuffer[FBufferSize[color=#ff0000][b] + 1[/b][/color]], Length(S) * SizeOf(Char));
Code:
Aber schon witzig, daß es dennoch manchmal problemlos läuft. :shock:
[b]Procedure[/b] TTextStream.Flush;
[b]Begin[/b] [b]If[/b] FAccess <> saRead [b]Then Begin[/b] FByteBuffer := FEncoding.GetBytes([color=#ff0000][b]Copy([/b][/color]FStringBuffer[color=#ff0000][b], 1, FBufferSize)[/b][/color]); Zitat:
Zum Glück muß ich Fehler jetzt nur noch in einer Version fixen :-D |
Re: TTextStream - Textdateien einlesen
Vielen Danke fürs fixen. :dp:
|
AW: TTextStream - Textdateien einlesen
Hi Himitsu,
ich benutze Deine Unit TextStream und habe dabei ein Problem und eine weitere Frage: 1. Wenn man eine Datei einliest, die UTF-8 codiert ist (mit! BOM), dann erhält man in der ersten Zeile als erstes "Zeichen" immer $FEFF (65279). Dies passiert nur, wenn man als Encoding beim Öffnen (=Create) TEncoding.UTF8 angibt. Lässt man das Encoding weg (nil), funktioniert es korrekt. Was kann man da machen? 2. Es scheint mir mit Deiner Unit nicht möglich zu sein eine UTF-8 codierte Datei ohne! BOM zu erzeugen, oder habe ich da etwas übersehen? Danke in Voraus Freejay |
AW: TTextStream - Textdateien einlesen
Joar, da hatte ich wohl ein bissl zuviel gelöscht.
1. sollte jetzt funktionieren. (die Prüfung wurde ausversehn mit entfernt) 2. joar, das war hier eigentlich nicht vorgesehn (in meiner größeren Version gibt es dafür eine interne Option ... hab dafür aber nun einen neuen Access-Wert eingeführt > saWriteWithoutBOM) #$FEFF ist das "Zeichen" für Unicode ... wenn man dieses Zeichen entsprechend kodiert, dann ergibt dieses das BOM der zugehörigen Kodierung. :angel: |
AW: TTextStream - Textdateien einlesen
Hallo,
erstmal TOP :thumb: Hab beim Überfliegen gerade gesehen, dass sich u.U. ein Copy&Paste-Fehler eingeschlichen hat. In Zeile 287-289 von
Delphi-Quellcode:
wird
Class Function TEncoding.GetASCII: TEncoding;
Delphi-Quellcode:
verwendet anstatt wahrscheinlich
FBigEndianUnicodeEncoding
Delphi-Quellcode:
.
FASCIIEncoding
Ist aber nur eine Vermutung. Gruß, Chris |
AW: TTextStream - Textdateien einlesen
Hallo Himitsu,
vielen Dank für die schnelle Antwort und Änderung! Respekt! Allerdings hat sich glaube ich da noch ein kleiner Fehler eingeschlichen. Mir wurden jetzt bei UTF8-ohne-Bom-Dateien auch die drei ersten Zeichen abgeschnitten. Ich habe dann die Zeile 638 von
Delphi-Quellcode:
auf
If (FBufferSize < i)...
Delphi-Quellcode:
geändert und jetzt scheint alles korrekt zu funktionieren.
If (FBufferSize >= i)...
Vielen Dank nochmal! Gruß Freejay |
AW: TTextStream - Textdateien einlesen
@Freejay:
Delphi-Quellcode:
wäre richtiger.
If (FBufferSize < i) or not CompareMem(@FByteBuffer[0], @B[0], i) Then i := 0;
(hab beim Umdrehen des äußeren IFs das AND vergessen mitzudrehen :wall: ) @ChrisE: ich seh nix :roll: danke Hatte dieses
Delphi-Quellcode:
auf jenes
If not Assigned(FEncoding) Then Begin
i := TEncoding.GetBufferEncoding(FByteBuffer, FEncoding); If i > 0 Then Begin Move(FByteBuffer[i], FByteBuffer[0], FBufferSize - i); Dec(FBufferSize, i); End; End Else Begin B := Encoding.GetPreamble; i := Length(B); If (FBufferSize >= i) and CompareMem(@FByteBuffer[0], @B[0], i) Then Begin Move(FByteBuffer[i], FByteBuffer[0], FBufferSize - i); Dec(FBufferSize, i); End; End;
Delphi-Quellcode:
gekürzt.
If Assigned(FEncoding) Then Begin
B := Encoding.GetPreamble; i := Length(B); If (FBufferSize < i) or not CompareMem(@FByteBuffer[0], @B[0], i) Then i := 0; End Else i := TEncoding.GetBufferEncoding(FByteBuffer, FEncoding); If i > 0 Then Begin Move(FByteBuffer[i], FByteBuffer[0], FBufferSize - i); Dec(FBufferSize, i); End; |
AW: TTextStream - Textdateien einlesen
Zitat:
kein Problem |
AW: TTextStream - Textdateien einlesen
@himutsu
Alles klar! Danke! |
AW: TTextStream - Textdateien einlesen
Hallo himitsu,
TTextStream (ohne "Ex") funktioniert jetzt bei mir tadellos! Aber ich verstehe TTextStreamEx (mit "Ex") überhaupt nicht... Folgender simpler Alltags-Code führt z.B. dazu, dass sich das Programm aufhängt:
Delphi-Quellcode:
Meine Vermutung war: Die Funktion EoLn ist genau falsch herum definiert:
TextStream := TTextStreamEx.Reset(FileName,FEncoding);
TextStream.ReadLn(sHeader); Statt
Delphi-Quellcode:
müsste es meiner Meinung nach
Result := Trim(FLine) <> '';
Delphi-Quellcode:
heißen.
Result := Trim(FLine) = '';
Dann bekommt man zwar soetwas ähnliches wie die erste Zeile geliefert, aber eben nicht genau. Meine Zeile enthält z.B. TABs: Die sind verschwunden und stattdessen sind an ihrer Stelle Leerzeichen. Die Zeile wird also irgendwie zerstückelt und anschließend zusammengesetzt, da bei ReadLn die Funktion ReadFull aufgerufen wird, die sozusagen einzelne Werte aus einer Zeile einliest und anschließend mit Leerzeichen als Trenner wieder zusammensetzt. So gehen mehrfache Leerzeichen, TABs und möglicherweise noch andere Dinge aus der ursprünglichen Zeile verloren. Muss ich eine andere Methode benutzen oder habe ich TTextStreamEx blos nicht verstanden? Gruß Freejay |
AW: TTextStream - Textdateien einlesen
Hab grade kein Delphi hier, drum werd ich mir das später nochmals genauer ansehn.
Aber mit dem EoLn hast du Recht. Wenn nichts mehr am Zeilenende oder nur noch Leer-/ Steuerzeichen am Ende enthalten sind, dann muß es True werden, also
Delphi-Quellcode:
= ''
|
AW: TTextStream - Textdateien einlesen
Hallo Himitsu!
Ich habe mal folgendes probiert:
Delphi-Quellcode:
Dabei ist mir aufgefallen, daß die zweite Zeile einer Datei nicht ausgelesen wird. Meiner Meinung nach liegt dies wohl an der Art, wie die Funktion TTextStreamEx.ReadLine aufgerufen wird. Hier wird beim ersten Aufruf durch den EoLn Vergleich zwei mal das ReadLine aufgerufen. Wenn man es wie nachfolgend macht klappt es:aFile := 'C:\Users\D. Jan Schulz\Desktop\Iris-Tab - Kopie UTF8.txt'; F := TTextStreamEx.Create(aFile, saRead); Try Memo1.Clear; While not f.EoF do Begin aString := f.ReadLine; Memo1.Lines.Add(aString); end; Finally F.Free; end;
Delphi-Quellcode:
Ich bin mir jetzt aber nicht sicher, wie dieser Eingriff sich mit anderen Funktionen verhält. Ich fange gerade erst an mich mit der Unit zu beschäftigen. Vielleicht kannst du mit etwas mehr Hintergrundwissen da etwas zu sagen. Das Gleiche scheint auch zu gelten für TTextStreamEx.ReadLn.Function TTextStreamEx.ReadLine: SString; Begin If EoLn Then Begin Result := inherited ReadLine; // FLine := inherited ReadLine; //Zeile 1429 FLine := Result; End Else Begin Result := FLine; FLine := inherited ReadLine; End; End; Vielleicht wäre es auch gut die einzelnen FFormat Einstellungen als Property nach außen zu veröffentlichen, da man oftmals Dateien mit unterschiedlichen Ländereinstellungen vorfindet. FIndex könnte man auch nach außen legen, um gezielt einzelne Zeilen anzuspringen. Wenn ich das bislang richtig sehe, dann hast du dies ja sehr gut beim Create in der FLines Struktur abgelegt. Es müsste natürlich dann eine Kontrolle stattfinden, ob der gewählte Wert innerhalb der Ranges von FLines liegt. Aber damit könnte man dann auch 're-parsing' machen wenn man die FFormats geändert hat... Aber wie gesagt, ich fang da gerade erst mit an und hab sicherlich noch nicht alles in deiner Unit verstanden... Jan |
AW: TTextStream - Textdateien einlesen
Liste der Anhänge anzeigen (Anzahl: 1)
[edit] Sekunde, bin och blöd ... werd's gleich nochmal probieren, mit der richtigen Klasse :oops: und mich dann wieder melden.
[add] Die Funktion ReadLine sollte aber korrekt sein und ich vermute mal einen Fehler im .Create, denn sonst würde nicht nur die 2. Zeile fehlen, sondern womöglich jede Zweite. [add2] Also, ein
Delphi-Quellcode:
im .Create könnte nicht schaden und das Problem mit der fehlenden Zeile ... es liegt daran, daß es ein "kleines" Problemchen mit "leeren" Zeilen gibt.
Inherited ReadLine
Da hatte ich damals in meiner Testdatei wol keine drin. Muß mir dafür nur noch was überlegen, denn ich hatte den LeerString quasi als "Markierung" für das Zeilenende genutzt, so daß er nun Leerzeilen überspringt, aber ich hab schon eine Idee (muß nur noch ausprobieren ob's geht). Hmmm, ich hab mir nochmal schnell ein kleines Testprogramm erstellt und da scheint es diesbezüglich keine Probleme zu geben. :gruebel:
Delphi-Quellcode:
(das Copy, falls die Zeile länger ist, als die Konsole breit)
Program Project1;
{$APPTYPE CONSOLE} Uses SysUtils, TextStream; Var S: TTextStream; i: Integer; Begin Try S := TTextStream.Create('TextStream.pas', saRead); i := 0; While not S.EoF and (i < 15) do Begin WriteLn(Copy(S.Line, 1, 79)); Inc(i); End; S.Free; ReadLn; Except On E: Exception do Begin WriteLn(E.ClassName, ': ', E.Message); ReadLn; End; End; End. Aber vielleicht liegt es ja an einer, wie die Juristen gern sagen, Verkettung unglücklicher Umstände? Kannst du mir mal dein (Test)Projekt und die zu lesende Datei zukommen lassen? OK, das mit dem FFormat war garnicht geplant es nach außen weiterzugeben, da ich intern so sicherstellen wollte, daß hiermit "gespeicherte" Daten überall korrekt gelesen werden können, egal welche Ländereinstellung im System vorliegen. Auf die Idee daß man auch andersweitige Dateien damit leden können wöllte, bin ich garnicht gekommen. :oops: Läßt sich aber leicht nachrüsten :D
Delphi-Quellcode:
und dann unten noch das rein
Constructor Append (Filename: SString; Encoding: TEncoding = nil; OwnsEncoding: Boolean = False);
Destructor Close; Property NumberFormat: TFormatSettings Read FFormat; Procedure SetNumberFormat(Const Format: TFormatSettings); Procedure Read (Var Value: SString); Overload;
Delphi-Quellcode:
Procedure TTextStreamEx.SetNumberFormat(Const Format: TFormatSettings);
Begin FFormat := Format; End; |
AW: TTextStream - Textdateien einlesen
Liste der Anhänge anzeigen (Anzahl: 1)
Hatte aber noch nicht die Gelegenheit alles zu Testen, darum quasi nur erstmal als PreAlpha, oder so :stupid: , da es so einige Änderungen gab.
[edit] Anhang entfernt (Aktuelleres siehe Post #1) |
AW: TTextStream - Textdateien einlesen
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo Himitsu,
habe am Wochenende mal deine Neuerungen getestet. Die Probleme scheinen sich jetzt gelöst zu haben. Ganz klar ist mir allerdings noch nicht was intern mit deinem fIndex passiert. Ich habe diese Variable mal als Property ActualRow in tTextStream nach außen gelegt:
Delphi-Quellcode:
Das funzt auch. Der Vorteil ist (aus meiner Sicht), daß man den Zeiger auf eine beliebige Stelle innerhalb der Datei setzen kann. Es ermöglicht, z.B. bei der Verwendung in einem Import-Wizard, daß man die Datei neu parsen kann, wenn irgendwelche Einstellungen verändert werden sollen. Neben der aktuellen Zeile hat man dann auch gleichzeitig noch die Angabe wie viele Zeilen (mit Wiederholungen) überhaupt schon verarbeitet wurden über f.GetProcessedLines.
Property ActualRow: Integer Read fIndex Write fIndex;
Soweit ich das richtig verstanden habe ist fIndex ein Null-basierter Index, der in fLines verwendet wird. Nutze ich das mit dem folgenden Code:
Delphi-Quellcode:
Bekomme ich die erste Zeile zwei mal, wobei GetProcessedLines schon vorher auf 1 steht und sich von fLines unterscheidet.
procedure TForm1.Button1Click(Sender: TObject);
Var f: tTextStreamEx; aFile : String; astring : UnicodeString; aRunner : Integer; aString2: String; aString3: UnicodeString; aBytes : tBytes; aSize : Integer; aLineNo : String; begin aFile := 'C:\Users\D. Jan Schulz\Desktop\Iris-Tab - Kopie UTF8.txt'; F := TTextStreamEx.Create(aFile, saRead); Try Memo1.Clear; aBytes := f.Encoding.GetPreamble; Memo1.Lines.Add('Byte sequence:' + PWidechar(aBytes)); aString2:= f.Encoding.ToString; Memo1.Lines.Add('BOM code: ' + aString2); Memo1.Lines.Add(IntToStr (ord (f.LineBreak))) ; aSize := f.CRLFCounter; Memo1.Lines.Add('CRLF count: ' + IntToStr(aSize)); aSize := f.LFCounter; Memo1.Lines.Add('LF count: ' + IntToStr(aSize)); aSize := f.CRCounter; Memo1.Lines.Add('CR count: ' + IntToStr(aSize)); f.ActualRow := 0; // Unterschied, wenn diese Zeile auskommentiert ist While not f.EoF do Begin aLineNo := IntToStr(f.ActualRow) + '/'+IntToStr(f.GetProcessedLines) + ': '; aString := f.ReadLine; Memo1.Lines.Add(aLineNo + aString+ '-> '+ IntToStr(f.ActualRow) + '/'+IntToStr(f.GetProcessedLines)); End; Finally F.Free; End; end; Kommentiere ich im obigen Beispiel die markierte Zeile aus, habe ich eine korrekte Auslesung und beide Werte sind identisch (ebenso als wenn ich f.ActualRow auf 1 setze). Ist der doch nicht Null-basiert? Zusätzlich ist mir aufgefallen, daß du offensichtlich feste Delimiter verwendest. Oftmals wird aber auch das Leerzeichen genutzt oder irgendwelche mystischen Symbole. Dadurch ist deine Arbeit mit den schönen ReadValues nur bedingt universell. Das gleiche gilt für Quote-Zeichen. Hier wird neben " auch oftmals ' verwendet oder irgendwas anders (hab schon mal ein @ gesehen). Aus dem Grund wäre es sicherlich gut, wenn man dies Zeichen frei definieren kann. Was in der Praxis auch schwierig ist, ist die Tatsache, daß ein ReadValue sofort eine Exception wirft, sobald ein falsches Format vorliegt. Hier wäre sicherlich noch eine weitere Funktion sinnig, die einen Wert zurückgibt, der nach den Ländereinstellungen des Rechners umgeschrieben wurde (Dateien mit Komma als Dezimaltrenner, aber mit Punkt auf dem Zielrechner) und einfach den ausgelesenen String, wenn die Wandlung nicht möglich war (z.B. ein Datum, Zeit, Kommentar oder ähnliches). Oftmals benötigt man die Daten weiterhin als String, aber hätte gerne die Formatierung auf das aktuelle System umgeschrieben. Besonders in gemischten Dateien. Jan PS: Ich hab mal vorsichtshalber meine Testdatei angehängt. Es ist der klassiche Iris Datensatz mit einer UTF8-Präambel. PPS: Sicherlich sind einige Anmerkungen nur relativ selten vorkommende Fälle. Wenn man aber viel mit solchen Daten zu tun hat, dann stolpert man sehr häufig über solche Sonderfälle. Stell dir mal vor ein Amerikaner und ein Russe (mit jeweils eigenen Ländereinstellungen) erzeugen Daten und migrieren diese auf einem Rechner, der eine deutsche Ländereinstellung verwendet. Lustige Kombinationen von Dezimal- & Tausendertrennzeichen sind die Folge, ebenso wie Datumswerte... Teilweise werden auch Mehrere Trennzeichen (z.B.) Space hintereinander geschrieben, die man dann als ein zeichen interpretieren muss. Und dabei meine ich KEINE festen Spaltenbreiten. z.B. immer 4 Space Zeichen, und dann die Werte/Informationen in unterschiedlicher Länge... |
AW: TTextStream - Textdateien einlesen
Zitat:
Ich lese die Datei ja blockweise ein, die Zeilen im aktuellen Block werden über FLines indiziert. FIndex gibt nun an, wieviel von diesem Block schon eingelesen wurde, bzw. an welcher Stelle (Index) man sich dort grade befindet und ob bei einem ReadLine nun noch eine Zeile aus diesem Puffer genommen werden kann, oder ob ein neues Stück geladen+geparst werden muß. Das mit dem Quote-Zeichen sollte kein Problem sein. Die Anzahl der Trennzeichen sollte egal sein. Über das enthaltene TRIM werden mehrere nachfolgene Trennzeichen zusammengefasst. Ich könnte eventuell aber eine Art StrictDelemiter einführen, wo dann immer nach jedem Leer-/Trennzeichen geteilt und nichts zusammengefaßt wird. Dieses .ActualRow hat mich noch auf die Idee gebracht, daß man auch noch die Spalte mitzählen könnte, wenn die Zeilen "Value"-weise ausgelesen werden. Na mal sehn, was sich noch so machen läßt. [add] aktuelle Testversion siehe Beitrag #1 |
AW: TTextStream - Textdateien einlesen
Hallo,
ich habe mir mal deine Klasse runtergeladen und unter Windows XP funktioniert sie. Jetzt habe ich versucht meine Applikation auf einem Windows7 32Bit System zu starten und er kommt an der Stelle zu scheitern, wenn ich versuche den Textstream zu erstellen. Ich rufe folgendes beim Initialisieren auf:
Delphi-Quellcode:
Hoffe auf baldige Hilfe!!!
var myFile : TTextStream;
... myFile := TTextStream.Create(ChangeFileExt(Application.Exename, '.lng'), saRead); try ... finally myFile.Free; end: Danke & Gruß, Moony |
AW: TTextStream - Textdateien einlesen
Gut, dann erstmal ganz allgemein gefragt:
Wo liegt eine EXE und sicher daß dein Programm dort über ausreichende Zugriffsrechte verfügt? |
AW: TTextStream - Textdateien einlesen
Die Exe liegt in einem Ordner auf dem Desktop. Für diesen User ist bekanntlich in dem Userordner Schreibzugriff drauf.
|
AW: TTextStream - Textdateien einlesen
Gut, bei Win7 war's halt naheliegend, daß es daran liegen könnte, wenn es unter XP noch geht. :stupid:
Hmmm, wie heißt denn die Fehlermeldung und kannst du zufällig die Zeile nennen, in welcher es knallt? Eigentlich wäre es sehr ungewöhnlich, wenn es genau in dieser Zeile knallt.
Delphi-Quellcode:
.
myFile := TTextStream.Create(ChangeFileExt(Application.Exename, '.lng'), saRead);
Ich glaub die Debuginfos hatte ich zu diesen Units nicht abgestellt, weswegen ich eher glauben würde der Debugger sollte weiter reingehn. :gruebel: Notfalls mal einen Haltepunkt auf diese Zeile, dann Schritt für Schritt mit F7 weitergehn und die Zeile merken, welche aktiv war, bevor es knallte. |
AW: TTextStream - Textdateien einlesen
Nee, es kracht genau dort. Leider kann ich nicht debuggen, weil ich auf WinXp entwickel und die Applikation auf einem Win7 laufen soll.
Ich habe versucht mir Messages und ein Tracefile zu schreiben. Er ist bis zu der Create-Zeile mit den Messages gekommen und danach kam schon die Meldung dass die Funktion mit einer Exception beendet wurde. |
AW: TTextStream - Textdateien einlesen
Guten Morgen,
hmm, keine weitere Hilfe oder Idee zur Hand??? Gruß, Moony |
AW: TTextStream - Textdateien einlesen
Tschuldschung.
Kann es zur Zeit schlecht testen/debuggen, abgesehn davon, daß ich die letzten Tage flach lag und fast keinen klaren Gedanken fassen konnte. :vernupft: |
AW: TTextStream - Textdateien einlesen
Kein Problem....Gesundheit geht vor.
Debuggen kann ich leider auch nicht, sonst hätte ich das schon gemacht. Die Frage wäre dann nur wie kommen wir dem Problem auf die Schliche? Gruß, Moony |
AW: TTextStream - Textdateien einlesen
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:22 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-2025 by Thomas Breitkreuz