Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi schnelles Textzeilen auslesen ab Position x (https://www.delphipraxis.net/73218-schnelles-textzeilen-auslesen-ab-position-x.html)

dose 13. Jul 2006 21:14


schnelles Textzeilen auslesen ab Position x
 
Hallo Delphi'ler

Leider muß ich gleich meinen ersten Beitrag als Frage formulieren, aber ich verspreche Besserung.

Ich habe über die Suchfunktion eine ganze Reihe Beiträge gefunden die sich mit dem Zeilenweisen auslesen von Dateien beschäftigen.
Leider muß ich ein existierendes Dateiformat öffnen und ab Position x im File anfangen zu lesen ohne vorher das gesamte File durchlaufen zu müssen (Also Datei binär zugreifen und Seek-Komando...). Die Dateien sind teilweise relativ groß 100-200 MB, weshalb zum Beispiel das Einlesen in eine TStringlist ausscheidet.

Das ganze soll natürlich sehr effektiv und schnell erfolgen.
Ich habe es bereits kurz zusammen programmiert über den Zugriffstyp binär mit "File of Byte" zeichenweise jedes Byte ausgelesen und exemplarisch in ein Datenfeld zu schreiben, jedoch war die Geschwindigkeit sehr langsam.

Beim Suchen im Internet habe ich diese Seite gefunden
http://www.delphifaq.com/faq/f87.shtml
die ungefähr das realisiert was ich möchte nur eben verkehrt.

Daher 2 Fragen:
1. Was mache ich grundsätzlich falsch wenn ich zeichenweise die Daten auslese? Warum ist ein Buffer effektiver?
2. Wie realisiere ich so etwas prinzipiell, da ich ja das Zeilenende erst mit dem chr(13) bzw. (10) erkenne?

Viele Grüße
...und danke für den Fisch...

dose

Christian Seehase 13. Jul 2006 21:31

Re: schnelles Textzeilen auslesen ab Position x
 
Moin Dose,

erst einmal herzlich willkommen hier in der Delphi-PRAXiS.

Wenn Du nicht byteweise durchgehst, sondern einen Buffer verarbeitest, kannst Du selber bestimmen, wie gross der Buffer ist, denn ein Buffer wird intern auf jeden Fall angelegt (ich weiss jetzt allerdings nicht wie gross).

Wenn Du es mit TFileStream machst, könntest Du die Stelle aber der Du lesen willst direkt mit der Eigenschaft Position angeben.
Ab dieser Stelle füllst Du Deinen Buffer und verarbeitest ihn. Dies dann so lange, bis Du das gewünschte gefunden, oder alles gelesen hast.
Da Du ja offensichtlich nicht nur Strings in der Datei hast (sonst könntest Du ja einfach zeilenweise lesen), stellt sich mir die Frage, ob Du nicht eventuell auch Records verwenden könntest um die Nicht-Strings zu lesen.

3_of_8 13. Jul 2006 21:35

Re: schnelles Textzeilen auslesen ab Position x
 
Ein array of Byte/Char wäre als Buffer gut geeignet.

Hawkeye219 13. Jul 2006 21:51

Re: schnelles Textzeilen auslesen ab Position x
 
Hallo dose,

vielleicht kannst du ja die Unit File64 von himitsu benutzen. Sie enthält u.a. eine Seek-Funktion, die auch mit Textdateien arbeitet.

Gruß Hawkeye

dose 7. Aug 2006 07:20

Re: schnelles Textzeilen auslesen ab Position x
 
Hallo,
Vielen Dank für die Tips.
Ich habe mir die Unit File64 angeschaut, aber leider funktionieren dort die Positionszeiger nicht so ganz sauber wie ich mir das vorstelle. Daher möchte ich das lieber auf 32 bit realisieren.

Anbei mein Code, der eine Datei durchforstet und jeweils bei CrLf eine neue Zeile ausgibt. (Siehe Ausgabe).
Ich habe trotzdem das Gefühl dass das nicht sonderlich Performant (vermutlich zuviele Variablenzuweisungen) ist, bzw. teilweise sogar nicht sauber funktioniert. (wenn Startposition und Endposition nicht die gesamte Datei beinhalten).
Prinzipiell arbeitet der Code so, dass der den Buffer dessen größe in MAXLINELENGTH festgelegt wird in eine Variable ließt und untersucht. Der Rest nach dem Zeilenumbruch wird dann in die Variable Linebuffer übernommen und die Abarbeitung beginnt von neuem.

Habt jemand von euch noch einen optimierungs Tip? Ich wäre sehr dankbar.



Delphi-Quellcode:
const
  MAXLINELENGTH = 128;
  FileName = 'c:\in.file';
var
  curr, feof, readlen, tmppos: Longint;
  startpos, Stoppos: Longint;
  Buffer : array [0..MAXLINELENGTH] of char;
  p     : PChar;
  f          : integer;
  Line       : string;
  LineBuffer : string;
  text : string;

begin

  f := FileOpen (FileName, 0);

  feof := FileSeek (f, 0, 2);
  // feof = Größe der Datei (wo das Lesen


  Startpos := 0;
  // Startpos setzt den Dateizeiger dorthin wo das Einlesen begonnen werden soll
  Stoppos := feof;
  // Wir wollen jetzt mal exemplarisch die gesammte Datei bearbeiten...


  FileSeek (f, 0, 0);
  // Dateizeiger an den Anfang der Datei

  curr := FileSeek (f, 0, 1);
  // Aktuelle Position in curr einlesen
  LineBuffer := '';
  while (curr < stoppos do
   begin
      if ((curr + MAXLINELENGTH )> stoppos then
        begin
           readlen := stoppos- curr;
        end
      else
        begin
           readlen := MAXLINELENGTH;
        end;
      FileRead(f, Buffer, readlen);
      p := StrScan (Buffer, #10);
      if p = Nil then
        begin
          if (StrScan (Buffer, #13) = Nil) then
            begin
              Line := Copy(Buffer,0,MAXLINELENGTH);
            end
          else
            begin
              Line := Copy(Buffer,0,MAXLINELENGTH-1);
            end;
          LineBuffer := LineBuffer + Line;
        end
      else
        begin
          Line := Copy(Buffer,0,(p-@Buffer-1));
          text := LineBuffer + Line;
          LineBuffer := '';
          FileSeek (f, 0-readlen+(p-@Buffer)+1, 1);


          Memo1.Lines.Add(text);
     // Exemplarische Ausgabe


        end;
      curr := FileSeek(f, 0, 1);
   end;
  FileClose (f);
end;

3_of_8 7. Aug 2006 08:40

Re: schnelles Textzeilen auslesen ab Position x
 
Ich glaube recht viel performanter wirst dus nicht hinkriegen - eine Festplatte hat halt immer noch Zugriffszeiten im Millisekundenbereich, ein Prozessor verarbeitet deinen Code im Mikrosekundenbereich.

Das heißt die Festplatten sind einfach zu langsam für sowas.

marabu 7. Aug 2006 08:41

Re: schnelles Textzeilen auslesen ab Position x
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo.

TextFile ist zwar ein alter Hut, aber wenn es dich nicht stört, dann kannst du die darin enthaltene Puffertechnik verwenden und bequem mit ReadLn und WriteLn auf die Textzeilen zugreifen. Wenn ich beim Anpassen meiner alten TP-Quellen keinen Fehler gemacht habe, dann funktioniert prinzipiell das hier:

Delphi-Quellcode:
{$I Func.TextFilePos.pas}
{$I Func.TextFileSeek.pas}

procedure ReadLines(const fn: TFileName; startPos, numLines: Cardinal; s: TStrings);
var
  tf: TextFile;
  line: String;
begin
  AssignFile(tf, fn);
  Reset(tf);
  // SetTextBuf() hier, wenn nötig
  TextFileSeek(tf, startPos);
  while not Eof(tf) and (s.Count < numLines) do
  begin
    ReadLn(tf, line);
    s.Add(line);
  end;
  CloseFile(tf);
end;

procedure TDemoForm.ButtonClick(Sender: TObject);
begin
  with OpenDialog do
    if Execute then
      ReadLines(FileName, 1, 1, Memo.Lines);
end;
Grüße vom marabu

dose 7. Aug 2006 11:38

Re: schnelles Textzeilen auslesen ab Position x
 
Vielen Dank, das ist eine super alternative und wesentlich schneller.

gruß
dose9


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:26 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