Delphi-PRAXiS
Seite 2 von 2     12   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Effizientes Einlesen und Verarbeiten von Textdatei (https://www.delphipraxis.net/210935-effizientes-einlesen-und-verarbeiten-von-textdatei.html)

Andreas13 1. Jul 2022 17:08

AW: Effizientes Einlesen und Verarbeiten von Textdatei
 
@Uwe :thumb:
Das hat den Vorteil einer seeeehr genauen Zeitmessung, weil die intern verwendete Funktion
Delphi-Quellcode:
QueryPerformanceCounter
einen "High Resolution Counter" mit einer Genauigkeit von 0.00083 ms (!) abfragt.
Gruß, Andreas

Dalai 1. Jul 2022 19:31

AW: Effizientes Einlesen und Verarbeiten von Textdatei
 
Zitat:

Zitat von Neutral General (Beitrag 1508272)
Ich hoffe das war halbwegs verständlich (Erklären ist nicht immer so einfach :mrgreen:)

Ja, das ist verständlich. Danke! :thumb: Nun ist klar, warum es knallen musste. Endlich kann ich auf die Zwischenvariable verzichten.

-----

Zwischenzeitlich hatte ich auch einen anderen Weg getestet, bei dem keine Strings aus der Liste gelöscht werden und stattdessen eine Variable mit der aktuellen Zeile hochgezählt wird, ab der in der Schleife gesucht wird. Der Unterschied in der Laufzeit war zu vernachlässigen. Mit den ordentlichen Zeitmessungen muss ich mich noch beschäftigen.

Grüße
Dalai

Dalai 2. Jul 2022 19:02

AW: Effizientes Einlesen und Verarbeiten von Textdatei
 
Nach ein paar Tests mit TStopwatch und einer absichtlich großen PEM-Datei (etwas über 1 MiB) stelle ich Folgendes fest:
  1. Das Problem ist nicht so groß wie es anfänglich schien. Externe Speicherlecksucher schauen eben genauer hin, was seine Zeit braucht. Das hat mich glauben lassen, die Implementation an sich wäre langsam. Naja, im Vergleich mit anderen ist sie das auch, siehe nächster Punkt :)
  2. Der Weg mit dem Löschen der Strings ist trotzdem langsamer ist als Hochzählen eines Index

Das Verarbeiten der Textdatei (nach LoadFromFile!) mittels Löschen von Strings - siehe OP - dauert um die 200ms, mit dem Hochzählen des Index nur zwischen ca. 20 und 40ms.

Ich habe mich nun für das Hochzählen des Index mit folgender Implementation entschieden:
Delphi-Quellcode:
procedure NameNotRelevant;
var
  Lsl: TMyStringList;
  LidxH, LidxF: integer;
  Lheaderpresent: Boolean;
  Lstr: string;
begin
    Lsl:= TMyStringList.Create;
    try
      Lsl.LoadFromFile(FFileName);
      LidxF:= 0;
      Lheaderpresent:= False;
      repeat
          LidxH:= Lsl.IndexOf(PEM_HEADER, LidxF);
          LidxF:= Lsl.IndexOf(PEM_FOOTER, LidxF+1);
          if LidxH < 0 then begin
            if NOT Lheaderpresent then
                NameNotRelevant2(Lstr);
          end else begin
            Lheaderpresent:= True;
            Lstr:= Trim(Lsl.StringsBetween(LidxH+1, LidxF-1));
            NameNotRelevant2(Lstr);
            Inc(LidxF);
          end;
      until LidxH < 0;
    finally
      Lsl.Free;
    end;
end;

procedure NameNotRelevant2(const ACertStr: string);
var
  Lblob: CERT_BLOB;
begin
    if Length(ACertStr) = 0 then Exit;
    Lblob.cbData:= Length(ACertStr) * SizeOf(Char);
    GetMem(Lblob.pbData);
    try
      Move(ACertStr[1], Lblob.pbData^, Lblob.cbData);
      // Do something with Lblob
    finally
      FreeMem(Lblob.pbData);
    end;
end;
IndexOf hab ich frecherweise aus dem Quellcode von TStrings.IndexOf kopiert und lediglich einen Parameter ergänzt:
Delphi-Quellcode:
function TMyStringList.IndexOf(const S: string; StartIndex: integer): integer;
begin
  for Result := StartIndex to GetCount - 1 do
    if AnsiCompareText(Get(Result), S) = 0 then Exit;
  Result := -1;
end;
Wieso gibt's davon eigentlich standardmäßig keine solche Überladung?

-----

Wenn jemand eine schnellere Variante hat, kann die gern gepostet werden.

Auf alle Fälle danke ich allen Postern für die rege Beteiligung! :dp:

Grüße
Dalai

Delphi.Narium 2. Jul 2022 21:03

AW: Effizientes Einlesen und Verarbeiten von Textdatei
 
Musst Du auf Groß-/Kleinschreibung achten bzw. nicht beachten?
Sind die zu suchenden Zeichenfolgen (PEM_HEADER bzw. PEM_FOOTER immer gleich geschrieben?

Im zweiten Fall könntest Du das AnsiCompareText weglassen. Das Dauer durchaus auch seine Zeit.

Uwe Raabe 2. Jul 2022 22:18

AW: Effizientes Einlesen und Verarbeiten von Textdatei
 
Ich würde einen Ansatz per TStreamReader vorschlagen. Dabei wird nicht erst die ganze Datei in den Speicher geladen und es sind weder IndexOf noch StringsBetween nötig:
Delphi-Quellcode:
uses
  System.SysUtils,
  System.Classes;

...

procedure NameNotRelevant;
var
  reader: TStreamReader;
  line: string;
  data: string;
begin
  reader := TStreamReader.Create(FFileName);
  try
    data := '';
    while not reader.EndOfStream do begin
      line := reader.ReadLine;
      if line = PEM_HEADER then begin
        data := '';
      end
      else if line = PEM_FOOTER then begin
        NameNotRelevant2(data);
        data := '';
      end
      else begin
        data := data + TrimRight(line);
      end;
    end;
  finally
    reader.Free;
  end;
end;

Dalai 4. Jul 2022 17:03

AW: Effizientes Einlesen und Verarbeiten von Textdatei
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1508284)
Ich würde einen Ansatz per TStreamReader vorschlagen. Dabei wird nicht erst die ganze Datei in den Speicher geladen und es sind weder IndexOf noch StringsBetween nötig:

Interessanter Ansatz, danke. Leider ist diese Variante in meinen Tests langsamer. Der Gesamtvorgang braucht zwischen 60 und 100 ms, mit der Stringliste gesamt zwischen 40 und 60 ms. Wie gesagt, das ist die Gesamtzeit, also Einlesen mit LoadFromFile und anschließende Verabeitung. Daher sind diese Zeitangaben nicht mit den o.g. vergleichbar.

Die Variante hat noch einen weiteren Nachteil: Dateien ohne Header werden nicht berücksichtigt. Ja, das hatte ich nicht erwähnt, und deshalb konnte das keiner sonst wissen.

Zitat:

Zitat von Delphi.Narium (Beitrag 1508283)
Musst Du auf Groß-/Kleinschreibung achten bzw. nicht beachten?

Die Frage hab ich mir auch gestellt. Aktuell weiß ich es nicht. Da muss ich noch im zugehörigen RFC nachgrasen, wie die Header auszusehen haben.

Zitat:

Im zweiten Fall könntest Du das AnsiCompareText weglassen. Das Dauer durchaus auch seine Zeit.
Nach meinen Messungen macht es kaum etwas aus, einzelne Millisekunden mehr bzw. weniger. Relevanter als die CPU-Zeit wäre in der Tat die Schreibweise.

Grüße
Dalai


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:59 Uhr.
Seite 2 von 2     12   

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz