AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Eigenes Zeichen für Zeilenende bei ReadLN
Thema durchsuchen
Ansicht
Themen-Optionen

Eigenes Zeichen für Zeilenende bei ReadLN

Ein Thema von Ginko · begonnen am 21. Mai 2013 · letzter Beitrag vom 23. Mai 2013
Antwort Antwort
Perlsau
(Gast)

n/a Beiträge
 
#1

AW: Eigenes Zeichen für Zeilenende bei ReadLN

  Alt 21. Mai 2013, 16:40
Er ist wohl der Meinung, dass eine StringListe für so große Dateien nicht geeignet wäre.
Vielleicht stimmt das ja auch:

Eben hatte ich einen Testdurchlauf gestartet mit einer ca. 285 MB großen Textdatei. Beim Versuch, diese Datei (nicht Zip einlesen, sondern vorher entpacken) direkt in eine Stringliste einzulesen, erhalte ich nach kurzer Zeit die Meldung, ich hätte zu wenig Arbeitsspeicher:
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:
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;
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 ...
Delphi-Quellcode:
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;
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?

Eben erhalte ich die Mitteilung, daß die erste Procedure mit Liste.LoadFromFile, wenn sie mit XE2 kompiliert wurde, fehlerfrei arbeitet.

Geändert von Perlsau (21. Mai 2013 um 17:34 Uhr) Grund: Nachtrag
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.757 Beiträge
 
Delphi 12 Athens
 
#2

AW: Eigenes Zeichen für Zeilenende bei ReadLN

  Alt 21. Mai 2013, 17:55
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
Erstmal hat eine 32-Bit-Anwendung nur maximal 2GB Speicher zur Verfügung und dann getht TStringList.LoadFromFile da schon ziemlich verschwenderisch mit dem Speicher um. Die Datei hat knapp 300MB, die zunächst als TBytes geladen werden. Dann schlägt das Encoding zu, das da nochmal die doppelte Menge drauf legt (wegen Unicode) und die Zeichen in einem Character Array ablegt (sind dann schon fast 900MB). Das nachfolgende Erzeugen des Unicodestring (600MB) schlägt dann fehl, weil offenbar der Speichermanager nicht mehr mitspielt (VirtualAlloc schlägt fehl).

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.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Perlsau
(Gast)

n/a Beiträge
 
#3

AW: Eigenes Zeichen für Zeilenende bei ReadLN

  Alt 21. Mai 2013, 18:16
Hallo Uwe, da hab ich wieder was dazugelernt Dafür danke ich dir

Als 64-Bit funktioniert es dann aber.
Hab mir eben mal kurz Lazarus installiert, mit dem der TE ja offenbar arbeitet:

Das war ein Irrtum, ich hatte es in XP-64 gestestet:
Zitat:
Dort gibt es keine Fehlermeldung, wenn ich dieselbe Datei mit LoadFromFile in eine Stringlist lade, und das auf XP Pro 32. Ergo könnte er doch zumindest eine Stringlist verwenden, um seine 200 MB-Datei einzulesen. Da scheint Lazarus gegenüber Delphi was voraus zu haben ... Allerdings scheint Lazarus Probleme mit Unicode-Dateien zu haben ... Naja, sei's drum, ich will da jetzt nicht tiefer einsteigen in die Programmierung mit Lazarus.
Unter XP-32 taucht dieselbe Fehlermeldung auch unter Lazarus auf ...

Man könnte jetzt natürlich TStringList ableiten, LoadFromStream überschreiben und für große Dateien effizienter implementieren.
Wer das kann? Mir wäre das zuviel an Aufwand ...

Geändert von Perlsau (21. Mai 2013 um 19:41 Uhr) Grund: Korrektur
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
10.055 Beiträge
 
Delphi 12 Athens
 
#4

AW: Eigenes Zeichen für Zeilenende bei ReadLN

  Alt 21. Mai 2013, 19:13
Man könnte jetzt natürlich TStringList ableiten, LoadFromStream überschreiben und für große Dateien effizienter implementieren.
Wer das kann? Mir wäre das zuviel an Aufwand ...
Naja, für LoadFromFile im Grunde meine Unit zum Einlesen und intern noch das Arrayhandling verbessern, das wars schon. Also so viel ist das nicht.
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
Ginko

Registriert seit: 30. Aug 2008
208 Beiträge
 
FreePascal / Lazarus
 
#5

AW: Eigenes Zeichen für Zeilenende bei ReadLN

  Alt 21. Mai 2013, 21:54
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:
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
Ich werde mir noch die Klasse von jaenicke ansehen. Danke für den Hinweis.

Geändert von Ginko (21. Mai 2013 um 22:08 Uhr)
  Mit Zitat antworten Zitat
hathor
(Gast)

n/a Beiträge
 
#6

AW: Eigenes Zeichen für Zeilenende bei ReadLN

  Alt 21. Mai 2013, 23:12
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

Geändert von hathor (21. Mai 2013 um 23:15 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#7

AW: Eigenes Zeichen für Zeilenende bei ReadLN

  Alt 22. Mai 2013, 00:24
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 (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
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Furtbichler
(Gast)

n/a Beiträge
 
#8

AW: Eigenes Zeichen für Zeilenende bei ReadLN

  Alt 22. Mai 2013, 07:11
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)
  Mit Zitat antworten Zitat
Ginko

Registriert seit: 30. Aug 2008
208 Beiträge
 
FreePascal / Lazarus
 
#9

AW: Eigenes Zeichen für Zeilenende bei ReadLN

  Alt 22. Mai 2013, 09:05
@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.

Darum solltest du dir die Größe des Streams zwischenspeichern, dann sollte das erheblich schneller vonstatten gehen
Das werd ich mal noch versuchen Danke für die Antworten nochmal. Hab den Beitrag grad übersehen...

Geändert von Ginko (22. Mai 2013 um 09:10 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:51 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