Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Programm mit TFilestreams zu langsam (https://www.delphipraxis.net/84028-programm-mit-tfilestreams-zu-langsam.html)

slang 10. Jan 2007 11:31


Programm mit TFilestreams zu langsam
 
Hallo!

Ich habe eine kleine Konsolenanwendung geschrieben, welche eine große Datei durchsuchen und bestimmte Zeichenfolgen ersetzen soll.
Erstmal soll die ASCII-Folge 139210 durch ASCII 32 ersetzt werden.
Danach sollen alle übriggebliebenen ASCII 13 durch ASCII 32 ersetzt werden.
Danach sollen alle übriggebliebenen ASCII 10 durch ASCII 1310 ersetzt werden.
Das Programm braucht leider für eine 16MB Datei schon ca. 5 Minuten.
Es soll aber für Dateien mit über 500MB (eventuell auch über 1GB) eingesetzt werden.
Kann mir jemand ein paar Tipps geben, wo ich was verbessern kann bzw. wo mein Programm ausgebremst wird?
Hier der komplette Quelltext:

Delphi-Quellcode:
program ersetze;

{$APPTYPE CONSOLE}

uses
  SysUtils,Classes;

var stream1: TFIleStream;
    stream2: TFileStream;
    Buf,Buf2,Buf3 : Byte;
    chSpace,chCR,chLF: char;
    a,b,c:integer;

begin
  a:=0;
  b:=0;
  c:=0;
  chSpace := #32;
  chCR := #13;
  chLF := #10;
  stream1 := TFileStream.Create('c:\test.unl', fmOpenRead);
  stream2 := TFileStream.Create('c:\test2.unl', fmCreate);
  try
    // Byteweise in Stream1 bis zum Dateiende lesen
    while stream1.Position < stream1.size do
     begin
      stream1.Read(Buf,sizeof(Buf));
      if Buf = 13 then // ASCII 13 gefunden -> nächstes Byte muss überprüft werden
       begin
        stream1.Read(Buf2,sizeof(Buf2));
        if Buf2 = 92 then // ASCII 1392 gefunden -> nächstes Byte muss überprüft werden
         begin
          stream1.Read(Buf3,sizeof(Buf3));
          if Buf3 = 10 then // ASCII 139210 gefunden
           begin // Statt ASCII 139210 wird ASCII 32 (Space) in die neue Datei geschrieben
            stream2.Write(chSpace,sizeof(chSpace));
            a := a + 1;
           end
          else // kein ASCII 10 an dritter Stelle -> ASCII 32 (Space) in neue Datei schreiben und 2 Bytes zurückspringen
           begin
            stream2.Write(chSpace,SizeOf(chSpace));
            stream1.Seek(-2,soFromCurrent);
            b := b + 1;
           end;
         end
        else // kein ASCII 92 an zweiter Stelle -> ASCII 32 (Space) in neue Datei schreiben und 1 Byte zurückspringen
         begin
          stream2.Write(chSpace,SizeOf(chSpace));
          stream1.Seek(-1,soFromCurrent);
          b := b + 1;
         end;
       end
      else if Buf = 10 then // Kein ASCII 13 gefunden -> Prüfen ob ASCII 10 gefunden wurde
       begin // ASCII 10 gefunden -> ASCII 1310 in neue Datei schreiben
        stream2.Write(chCR,SizeOf(chCR));
        stream2.Write(chLF,SizeOf(chLF));
        c:=c+1;
       end
      else
       begin // Kein ASCII 10 gefunden -> Buf in Datei schreiben
        stream2.Write(Buf,SizeOf(Buf));
       end;
     end;

  finally
    stream1.Free;
    stream2.Free;
  end;
  writeln('gefundene 0D5C0A: ' + IntToStr(a));
  writeln('gefundene 0D: ' + IntToStr(b));
  writeln('gefundene 0A: ' + IntToStr(c));
  Readln;
end.
MfG
slang

Robert Marquardt 10. Jan 2007 11:43

Re: Programm mit TFilestreams zu langsam
 
Wer einen TFileStream byteweise liest ist selber schuld wenn die Performance darniederliegt. Es wird nicht gepuffert.
Besorg dir doch die JCL von http://jcl.sf.net/daily und benutze einen gepufferten Stream. In JclStreams.pas ist dazu TJclBufferedStream enthalten.

marabu 10. Jan 2007 11:59

Re: Programm mit TFilestreams zu langsam
 
Hallo,

eine Alternative zum selbstgeschriebenen Programm wäre das GNU Text Utility TR (Translate). Auch damit sollten sich die soft breaks eliminieren lassen.

Grüße vom marabu

slang 10. Jan 2007 13:14

Re: Programm mit TFilestreams zu langsam
 
Und wie benutze ich diese JclBufferedStreams?

Robert Marquardt 10. Jan 2007 13:46

Re: Programm mit TFilestreams zu langsam
 
Delphi-Quellcode:
var
  stream1, stream2: TJclBufferedStream;
begin
  stream1 := TJclBufferedStream.Create(TFileStream.Create('c:\test.unl', fmOpenRead), True);
  stream2 := TJclBufferedStream.Create(FileStream.Create('c:\test2.unl', fmCreate), True);

  ... der Rest bleibt gleich
TJclBufferedStream versklavt den angegebenen Stream. Das True in Konstruktor setzt OwnsStream womit dann beim Free auch der versklavte Stream freigegeben wird.
Damit braucht man keine separate Variable fuer den Sklaven.

ralfiii 19. Sep 2008 12:46

Re: Programm mit TFilestreams zu langsam
 
????
Seh ich da was nicht?

Ich hab mal schnell den gepufferten Stream getestet und die Performance ist noch deutlich schlechter.

"normal" = 1671
"buffered" = 4187

Delphi-Quellcode:
uses JclStreams;

procedure TForm1.Button1Click(Sender: TObject);
var counter : integer;
    StartTime : LongWord;
{DEFINE UseBufferendStream}
{$IFNDEF UseBufferendStream}
    fs : TFileStream;
{$ELSE}
    fs : TJclBufferedStream;
{$ENDIF}
    by : byte;
const CIterations = 1000000;
begin
     StartTime:=GetTickCount;
     by:=$0f;
{$IFNDEF UseBufferendStream}
     fs := TFileStream.Create( 'C:\test.txt', fmCreate or fmShareDenyWrite   );
{$ELSE}
     fs := TJclBufferedStream.Create(TFileStream.Create( 'C:\test.txt', fmCreate or fmShareDenyWrite   ), True);
{$ENDIF}
     try
        for counter:=0 to CIterations-1 do
            fs.write(by, sizeof(by));
     finally
            fs.Free;
     end;
     Caption:=IntToStr(GetTickCount - StartTime);
end;

ralfiii 26. Sep 2008 14:45

Re: Programm mit TFilestreams zu langsam
 
* push *

Kein Kommentar dazu? Von niemanden?
(Ich mein, dass TJclBufferedStream nicht g'scheit funktioniert)

ralfiii 22. Okt 2008 16:35

Re: Programm mit TFilestreams zu langsam
 
Sollte es jemanden interessieren:
Das Schreiben hab ich mir noch nicht angesehen, aber beim Lesen gibt's auch eine Besonderheit die mir aufgefallen ist:

Die Abfrage von TJclBufferedStream.Size ist tödlich für die Performance!
Bei jeder Abfrage springt er zum Ende des Streams was den Cache eliminiert.

Also: Wenn die Filegrösse öfter gebracht wird (z.B. um den Fortschritt anzuzeigen: Am Anfang in einer Variable zwischenspeichern!

Ralf


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:25 Uhr.

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