![]() |
Eigenes Zeichen für Zeilenende bei ReadLN
Hallo,
Gibt es eine Möglichkeit das Zeichen, welches ein Zeilenende markiert, selbst zu bestimmen. Es geht dabei um das Zeilenweise einlesen einer Textdatei mit ReadLn. Also ich meine so etwas wie SetLineBreakStyle nur für ein eigenes Zeichen. (Die Textdatei ist sehr groß deshalb wollte ich zeilenweise einlesen) |
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Besteht die Datei denn aus einer einzigen Zeile oder wie?
|
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Nein, es sind mehrere Seiten in einer Textdatei (ein paar tausend Seiten), die ich gerne jeweils einzeln einlesen würde . Die Seiten haben auch LineBreaks aber ich möchte immer eine Seite komplett laden. Deshalb habe ich gedacht ich markiere Anfang unde ENde einer Seite mit einem speziellen Zeichen, welches dann als Anfang bzw. Ende des Buffers gilt, der mit ReadLn eingelesen wird.
|
AW: Eigenes Zeichen für Zeilenende bei ReadLN
kann man sich die Datei ungefähr so vorstellen?
Code:
Dann würde ein readln Zeile1 liefern, weiteres readln Zeile2 usw. Wenn Du dann im readln-gelieferten String nachschaust ob ein z.B. "$" am Ende vorkommt, dann wäre die Seite zuende und Du könntest einen neuen Buffer machen.
Zeile1#13#10
Zeile2#13#10 Zeile3#13#10 EndeSeite$#13#10 Zeile4#13#10 |
AW: Eigenes Zeichen für Zeilenende bei ReadLN
doppelpost sorry
|
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Danke für die Antworten !
Ja so könnte eine Seite aussehen. Zitat:
Wäre es auch möglich ReadLn umzuschreiben (also ein eigenes ReadLn zu schreiben) und wäre das dann schneller im einlesen, wenn man nur das entprechende Zeichen einsetzt ? |
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Wenn du es nicht über ein definiertes Seitenende-Zeichen lösen willst, wäre TFileStream auch noch interessant. Damit könntest du die Blockgröße angeben, die du lesen magst.
|
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Also irgendwie verstehe ich die Diskussion nicht so ganz. Wofür benötigt man ein extra Zeichen für Zeilenende, wenn doch bereits eines vorhanden ist? Dann schreibt Baumina plötzlich von einem Zeichen für das Seitenende, was aber von Ginko offenbar übersehen wird, hatte er doch nach dem Zeilenende gefragt, und Baumina schreibt weiterhin lustig vom Seitenende ... Wäre nett, wenn du, Ginko, einmal darüber aufklärst, ob du wirklich Zeilenende meintest oder doch Seitenende ...
Zitat:
Zitat:
Und vor allem: Wieso nimmst du nicht einfach eine Stringliste zum Einlesen? Das geht so saumäßig schnell, daß dir die Spucke wegbleibt :wink: |
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Die Textdatei resultiert aus der Umwandlung einer PDF-Datei in Text und sieht wie folgt aus.
Code:
Wobei hier § (in wirklichkeit ist es #12) einen neuen Seitenanfang kennzeichnet (der urspr. PDF-Datei).
Zeilentext #13#10
Zeilentext #13#10 ... §Zeilentext #13#10 Zeilentext #13#10 ... §Zeilentext #13#10 Zeilentext #13#10 ... Ich glaube baumina hat es auch richtig verstanden, allerdings gibt es bei mir (mit obiger Lösung) noch das Problem das hinter dem § Zeichen noch der Rest mitübernommen wird (§Zeilentext #13#10). |
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Zitat:
|
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Also wenn sie fertig ist sollte sie so an die 200Mb sein. Vielleicht eher nur groß ...
Stringliste sollte dann rausfallen... |
AW: Eigenes Zeichen für Zeilenende bei ReadLN
ReadLn dürft doch schon auf der Liste der gefährdeten Funktionen stehen.
Sie sind eh eingeschränkt (Kein Unicode-Support), Verursachen teilweise komische Fehler (umstellung auf TFileStream und Co-Methoden haben die Fehler verschwinden lassen) und könnten im Rahmen des zukünftigen LLV-Compilerprojektes entfernt werden. |
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Ist es bei TFileStream und Co-Methoden auch möglich mit Textdateien so zu arbeiten, dass nicht die ganze Datei in den Speicher geladen wird ?
|
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Zitat:
![]() ![]() ![]() |
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Delphi-Quellcode:
Also bei diesem Vorgang würde der Speicher nur um ca. die größe von tmpStr1 anwachsen ?
var
FileStrm1: TFileStream; tmpStr1, SuchWort: String; len: Cardinal; startpos: Integer ; begin FileStrm1:= TFileStream.Create(Dateiname,fmOpenRead or fmShareCompat); try SuchWort:= Edit2.Text SetLength(tmpStr1, Length(SuchWort)); startpos:= StrToInt(Edit3.Text); FileStrm1.Seek(startpos,soFromBeginning); FileStrm1.ReadBuffer(tmpStr1[1], Length(tmpStr1)); ShowMessage('Wort: ' + tmpStr1 +' || Position: ' +IntToStr(FileStrm1.Position)); finally FreeAndNil(FileStrm1); end; |
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Zitat:
Delphi-Quellcode:
Danach hast du in der zurückgelieferten Stringliste die ganze Textdatei. Nun kannst du die bearbeiten: z.B. Nach Seiten-Ende-Zeichen suchen und gegebenenfalls einen leeren Absatz in deine Darstellungskomponente (Memo, RichEdit) einfügen. Ein Zeilen-Ende-Zeichen benötigst du nicht extra, das ist ja schon in der Textdatei enthalten. Wenn du eigentlich Seiten-Ende statt Zeilen-Ende gemeint hattest, solltest du das auch mitteilen. Aber auch Seiten-Ende-Zeichen scheinen in deiner Datei bereits vorhanden zu sein. Ehrlich gesagt, ich verstehe dein Problem nicht. Oder besser: Schreib doch einmal genau, was dir Probleme macht.
procedure TForm1.TextEinlesen(Datei: String; Liste: TStrings);
begin if FileExists(Datei) then Liste.LoadFromFile(Datei) else ShowMessage('Die Datei existiert nicht.'); end; |
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Es soll auf der Seite im Text gesucht werden, allerdings benötige ich zum Suchergebnis zusätzlich Informationen, die am Ende einer Seite stehen, dehalb soll immer eine ganze Seite eingelesen werden.
Ich habe es jetzt erstmal so gelöst das ich einfach mal alle Linebreaks mit StringReplace gelöscht habe und nur das § Zeichen (bzw #12) durch einen Linebreak ersetzt habe. Allerdings geht mir dann die ursprüngliche Strukur verloren... |
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Zitat:
|
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Er ist wohl der Meinung, dass eine StringListe für so große Dateien nicht geeignet wäre.
|
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Dann hätte ich 200MB Speicherverbrauch wenn ich die ganze Datei in eine Stringlist laden würde...
|
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Ja und? Wozu hast du denn den Speicher in deinem Rechner? Ich meine, du kannst das ganze natürlich mit MemoryMappedFiles lösen, aber wozu der Aufwand in Gefilden von 200 bis 300 MB?
Meine Idee: 1. Lade Datei in StringListe 2. Gehe die Zeilen der StringListe durch 3. Wenn am Anfang einer Zeile kein "$" gefunden, dann kopiere die Zeile in eine zweite StringListe 4. Wenn am Anfang einer Zeile "$" gefunden (Jetzt weiß ich nicht, was mit dieser Zeile passieren soll. Das musst du wissen.), dann speichere die zweite StringListe ab, ode rmach was mit ihrem Inhalt 5. Wenn das geschehen gehe die Zeilen der ersten StringListe weiter durch 6. goto 3 |
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Zitat:
Zitat:
|
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Ja es soll im ganzen Text gesucht werden, Missverständnis.
Allerdings soll bei einem Fund, Informationen vom Ende der Seite (Seitenzahl etc.) an das Suchergebnis angehängt werden. Deshalb brauch ich bei ReadLn immer den Abschnitt bis zum Ende einer Seite... (Weil ich die Datei Zeilenweise durchsuche). Meine obige Lösung mit Stringreplace ist nur ein Übergangslösung. Für die reine Suche reicht sie aber vollkommen. |
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Hast du dir mal meinen Vorschlag näher angeguckt? Dann pack die Seitenende-Zeile noch mit in die zweite StringListe. Durchsuche die zweite StringListe und die zusätzlichen Informationen findest du dann immer in der letzten Zeile der zweiten StringListe.
|
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Ich schau mir das mal noch genauer an. Muss jetzt aber erstmal weg. Danke bis hier für die ANtworten.
|
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Hallo,
schau Dir bitte mal TFileStream genau an. Dann liest Du damit "zeichenweise". Immer wenn Du auf #12 stößt, weißt Du, dass eine Seite zuende ist. Ich versuche es mal mit Pseudocode:
Code:
erstelle eine Stringliste
erstelle einen Memorystream erstelle einen Filestream wiederhole lese ein Zeichen aus dem Filestream ist Zeichen = #12 kopieren den memorystream in eine Stringliste // hier enthält die Stringliste nun genau eine Seite mache hier die erforderlichen Arbeiten für diese Seite leer Stringliste leere memeorystream ist Zeichen <> #12 schreibe zeichen in memeorystream wiederhole bis Dateiende // Erforderlich für die letzte Seite, falls die nicht mit #12 enden sollte. ist der Memorystream nicht leer kopieren den memorystream in eine Stringliste // hier enthält die Stringliste nun genau eine Seite mache hier die erforderlichen Arbeiten für diese Seite Ende |
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Wie wäre es mit meinem entsprechenden Reader?
![]() Eine .reg Datei dieser Größe habe ich damit inkl. Parsen in unter 5 Sekunden in einem Baum angezeigt bekommen. |
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Zitat:
200 MB für die Datei und jedeils 2 Byte (Unicode) für jedes Zeichen während des Aufbaus der Ergebnisliste. AFAIK arbeitet hier die Delphi-Implementierung nicht gerade Speicherschonend. |
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Zitat:
Eben hatte ich einen Testdurchlauf gestartet mit einer ca. 285 MB großen ![]() Exception der Klasse EOutOfMemory mit der Meldung 'Zu wenig Arbeitsspeicher' aufgetreten. In meinem Rechner sind 4 GB Ram verbaut. Geöffnet sind ein Dateimanager, Seamonkey, Thunderbird und RadStudio 2009 nebst im Debug-Mode laufender Exe. Das kann's doch nicht sein :?:
Delphi-Quellcode:
Lese ich dagegen die Textdatei via ReadLn ein und weise dabei jedesmal der Stringliste die eingelesene Zeile zu, komme ich auf 7.654.474 Zeilen, die sich am Ende in der Stringliste befinden. Das verstehe ich nicht: Beim direkten Einlesen ist der Speicher angeblich zu klein, beim Zuweisen über ReadLn paßt's dann wieder rein ...
procedure TForm1.Button_TextClick(Sender: TObject);
Var Liste : TStrings; begin IF NOT OpenDlg.Execute THEN Exit; Liste := TStringList.Create; Try Liste.LoadFromFile(OpenDlg.FileName); Finally Liste.Free; End; end;
Delphi-Quellcode:
Es erfolgt keine Fehlermeldung, alle Zeilen der Datei wurden in die Stringliste übertragen. Wie kann es also sein, daß beim direkten Befüllen der Stringliste eine Meldung erscheint, der Arbeitsspeicher würde nicht ausreichen?
procedure TForm1.Button_TextClick(Sender: TObject);
Var Liste : TStrings; f : TextFile; Zeile : String; begin IF NOT OpenDlg.Execute THEN Exit; Liste := TStringList.Create; AssignFile(f,OpenDlg.FileName); Reset(f); Try WHILE NOT EOF(f) DO BEGIN ReadLn(f,Zeile); Liste.Append(Zeile); Label_Anzahl.Caption := IntToStr(Liste.Count); Application.ProcessMessages; END; Finally Liste.Free; CloseFile(f); Label_Anzahl.Caption := Label_Anzahl.Caption + ' ' + Zeile; End; end; Eben erhalte ich die Mitteilung, daß die erste Procedure mit Liste.LoadFromFile, wenn sie mit XE2 kompiliert wurde, fehlerfrei arbeitet. |
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Zitat:
Als 64-Bit funktioniert es dann aber. Man könnte jetzt natürlich TStringList ableiten, LoadFromStream überschreiben und für große Dateien effizienter implementieren. |
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Hallo Uwe, da hab ich wieder was dazugelernt :!: Dafür danke ich dir :thumb:
Zitat:
Das war ein Irrtum, ich hatte es in XP-64 gestestet: Zitat:
Zitat:
|
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Zitat:
|
AW: Eigenes Zeichen für Zeilenende bei ReadLN
So ich habs mal mit dem Filestream gemacht. Das geht gar nicht, also von der Geschwindgkeit her ...
Bei einer Textdatei von 8Mb brauchte das ca 36s, mit ReadLn und angepassten TextBuffer hingegen nur ca 65ms.
Delphi-Quellcode:
Ich werde mir noch die Klasse von jaenicke ansehen. Danke für den Hinweis.
var
FileStrm1: TFileStream; Ch: Char; GesLength: Integer; Gesucht,Seite: String; StrList1: TStringList; begin Gesucht:= ( UTF8Decode( Edit1.Text ) ); StrList1:= TStringList.Create; FileStrm1:= TFileStream.Create('Textdatei.txt',fmOpenRead); try GesLength:= 0; while FileStrm1.Position < FileStrm1.Size do begin Seite := ''; while (FileStrm1.Read(Ch, 1) = 1) and ( Ch <> #12 ) do //Seite in String speichern Seite := Seite + Ch; ... {Textsuche und weitere Auswertung, Ergebnisse in Stringlist speichern...} ... GesLength:= GesLength + SeitenLength + 1; end; finally FreeAndNil(StrList1); FreeAndNil(FileStrm1); end |
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Wenn die Textstruktur erhalten bleiben soll, muss man es auch so einlesen:
- zeilenweise vom Zeilenanfang bis Zeilenende #13#10 - seitenweise bis zum 1. Auftreten von #12, dann vom 1.Zeichen nach #12 bis zum nächsten #12 usw. Steuerzeichen: 0001100,0xc,12,FF=Form Feed - Setzt Cursor auf Zeilenvorschub einer vorangegangenen Zeile |
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Das ist auch nicht weiter verwunderlich :) schickst du doch den FileStream immer wieder an das Ende der Datei und dann zurück an die aktuelle Leseposition (
Delphi-Quellcode:
).
FileStrm1.Size
Darum solltest du dir die Größe des Streams zwischenspeichern, dann sollte das erheblich schneller vonstatten gehen ;)
Delphi-Quellcode:
var
FileStrm1: TFileStream; LStreamSize : Int64; // lokale Variable Ch: Char; GesLength: Integer; Gesucht,Seite: String; StrList1: TStringList; begin Gesucht:= ( UTF8Decode( Edit1.Text ) ); StrList1:= TStringList.Create; FileStrm1:= TFileStream.Create('Textdatei.txt',fmOpenRead); try GesLength:= 0; // Stream-Size merken LStreamSize := FileStrm1.Size; // und damit prüfen while FileStrm1.Position < LStreamSize do begin Seite := ''; while (FileStrm1.Read(Ch, 1) = 1) and ( Ch <> #12 ) do //Seite in String speichern Seite := Seite + Ch; ... {Textsuche und weitere Auswertung, Ergebnisse in Stringlist speichern...} ... GesLength:= GesLength + SeitenLength + 1; end; finally FreeAndNil(StrList1); FreeAndNil(FileStrm1); end |
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Es wird 2x geprüft, ob noch Zeichen da sind, und zwar einmal beim Abfragen der Position und dann nochmal ob das Lesen eines Zeichens funktioniert hat. Das ist nicht schön.
Ich würde eine Funktion schreiben, die genau eine Seite liefert und True/False, ob noch weitere Seiten zu erwarten sind.
Delphi-Quellcode:
Function ReadOnePage (myFileStream : TStream; Var Page : String) : boolean;
Const CharSize = SizeOf(Char); Var Ch : Char; Begin result := True; Page := ''; While myFileStream.Read(Ch,CharSize) = CharSize do if Ch=#12 then exit else Page := Page + Ch; result := false; End; // Der eigentliche Aufruf ist dann ziemlich selbsterklärend While ReadOnePage (myFileStream, Page) Do ProcessPage(Page) |
AW: Eigenes Zeichen für Zeilenende bei ReadLN
@Furtbichler Danke für den Hinweis, allerdings konnte mit der Funktion keinen wesentlichen unterschied merken, auch ca 36s für die Suche von ca 2200 Wörtern.
Zitat:
|
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Wie schon geschrieben, mit der MMF wie ich es mache, geht es natürlich deutlich schneller als zeichenweise aus der Datei selbst zu lesen.
Das Problem hatte ich als ich für einen Registryeditor die .reg Dateien einlesen wollte. Und dort konnte ich dann eine solche 350 MiB Datei in wenigen Sekunden komplett einlesen und parsen. |
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Zitat:
Wenn Du an der Performance herumschrauben willst, dann versuche mal, den Algorithmus zu verbessern. Ach, und nimm endlich Sebastian Jänicke's MMF-Teil. |
AW: Eigenes Zeichen für Zeilenende bei ReadLN
Zitat:
Zitat:
Den Teil hatte ich schon ausprobiert, allerdings wollte ich das "kleine Problem" nicht gleich mit einer neuen Unit erschlagen. Muss man auch nicht wenn man bauminas ersten Vorschlag etwas anpasst, dann hat man eine schnelle und einfache Lösung. Gut Jänicke's MMF-Teil ist noch ein wenig schneller, aber da habe ich auch noch ein Problem mit. Ich habe den Delimiter auf #12 gestellt um die Seiten ganz zu erfassen. Schaut man sich die Zeile (bzw. Seite) im Debugger an, fehlt allerdings das erste Zeichen einer Zeile (bzw. Seite) im zweiten Durchlauf. Das liegt sicher daran das ja sonst die zwei Zeichen #13#10 benutzt werden. Gibt es da noch eine Option die ich übersehen habe oder muss man was umschreiben ? |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:48 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