Delphi-PRAXiS
Seite 1 von 4  1 23     Letzte »    

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Große Textdateien spitten (https://www.delphipraxis.net/194214-grosse-textdateien-spitten.html)

muhael 29. Okt 2017 17:20

Delphi-Version: 7

Große Textdateien spitten
 
Hallo DP Team,

ich habe eine Funktion die große Textdateien in 4 Dateien splittet.
Nur diese Funktion ist "sehr" langsam, Sie benötigt für eine 1,5 GB große Textdatei 102 Sekunden.
Da die Dateien die mein Programm bearbeiten soll ungefähr in der Größenordnung von 3-4 GB liegen, braucht die Funktion dafür ca 4,5 Minuten und dies ist zu lang.

Gibt es eine Möglichkeit oder eine Funktion die das wesentlich schneller machen kann?
Wichtig zu wissen ist, dass die Datei nur Zeilenweise gesplittet werden kann.


Hier der Funktionscode;

Delphi-Quellcode:
  For i := 0 to 3 do
  begin
    AssignFile(F[i],ExtractFilePath(ParamStr(0)) + 'Test_' + IntToStr(i) + '.txt');
    ReWrite(F[i]);
  end;

  i := 0;
  AssignFile(ff,Epfad.Text);
  Reset(ff);
  while not eof(ff) do
  begin
    inc(i);
    ReadLn(ff, TestText);
    Case i of
      1: WriteLn(F[0],TestText);
      2: WriteLn(F[1],TestText);
      3: WriteLn(F[2],TestText);
      4: WriteLn(F[3],TestText);
    end;
    If i = 4 Then
      i := 0;
  end;
  CloseFile(F[0]);
  CloseFile(F[1]);
  CloseFile(F[2]);
  CloseFile(F[3]);
VG

Vielen Dank und Grüße

himitsu 29. Okt 2017 17:29

AW: Große Textdateien spitten
 
Wie lang sind die Zeilen?

Die einfachste Variante würde eine Vergrößerung des Caches bedeuten.
Die Uralten Funktionen AssignFile+TEXT nutzen einen Cache von 128 Byte je Datei und das ist natürlich extrems unökonomisch. (vorallem da alleine schon die Sektoren/Cluster des Datenträgers wesentlich größer sind)

Siehe OH von Reset/Rewrite.

Uwe Raabe 29. Okt 2017 17:31

AW: Große Textdateien spitten
 
Sehe ich das richtig: jede Zeile kommt in eine andere Datei und nach 4 Zeilen fängt es wieder von vorne an? In dem Fall kommst du um ein zeilenweises Lesen, wie es aktuell implementiert ist, wohl nicht herum.

Man könnte allenfalls noch was mit Textbuffern machen: Delphi-Referenz durchsuchenSetTextBuf

muhael 29. Okt 2017 17:35

AW: Große Textdateien spitten
 
Zitat:

Zitat von himitsu (Beitrag 1384479)
Wie lang sind die Zeilen?

Unterschiedlich groß. Die längste Zeile in meiner Testdatei ist 409 Zeichen lang.
Es kann aber sein, dass die Zeilen länger werden, da es sich um eine Fehlerdatei einer Datenintegritätsprüfung einer Datenbank handelt.

Hier mal eine Beispielzeile:
Warnung: 'Fibu Buch.-Blattname' existiert nicht. Buch.-Blattvorlagenname: ALLGEMEIN, Name: LOHN 02/06 Das Feld Buch.-Blattname in der Tabelle Fibu Buch.-Blattzeile hat eine Tabellenrelation auf das Feld Name in der Tabelle Fibu Buch.-Blattname. 'Fibu Buch.-Blattzeile' ist durch die folgenden Felder und Werte bestimmt: Buch.-Blattvorlagenname='ALLGEMEIN',Buch.-Blattname='LOHN 02/06',Zeilennr.='337000'




Zitat:

Zitat von Uwe Raabe (Beitrag 1384480)
Sehe ich das richtig: jede Zeile kommt in eine andere Datei und nach 4 Zeilen fängt es wieder von vorne an? In dem Fall kommst du um ein zeilenweises Lesen, wie es aktuell implementiert ist, wohl nicht herum.

Ungefähr ja, so war meine erste Idee.

Mein Programm analysiert diese Zeilen und diesen Prozess will ich beschleunigen indem ich die Datei in 4 gleich große Dateien splitte und in 4 Threads gleichzeitig bearbeite.

Rollo62 29. Okt 2017 17:40

AW: Große Textdateien spitten
 
Vielleucht könnte TStringReader schneller sein (glaub ich aber nicht), gibt es das in D7 ?
https://stackoverflow.com/questions/...iles-in-delphi

Ich würde eher versuchen Chunks in M;emory einzulesen, und die dann im Memory zu analysieren.

Rollo

himitsu 29. Okt 2017 19:19

AW: Große Textdateien spitten
 
Um es zu Beschleunigen willst du es also 5 Dateien lesen und 4 Dateien auf die "langsame" Platte schreiben?

Warum nicht die Datei einmal einlesen und dabei die gelesenen Zeilen direkt an die Threads weiterreichen?

muhael 29. Okt 2017 19:23

AW: Große Textdateien spitten
 
Zitat:

Zitat von himitsu (Beitrag 1384485)
Um es zu Beschleunigen willst du es also 5 Mal lesen und 4 Mal auf die "langsame" Platte schreiben?

Warum nicht die Datei einmal einlesen und dabei die gelesenen Zeilen direkt an die Threads weiterreichen?


Ich speichere ja die Werte zurück und Überprüfe daraufhin auf doppelte Werte. Da müssen ja dann die threads drauf warten bis die Überprüfung von einem thread fertig ist oder? 🤔

Glados 29. Okt 2017 19:28

AW: Große Textdateien spitten
 
Wie wäre es denn mit Memory Mapped Files von Herrn Jaenike?
Ließt unheimlich schnell ein und die Zeilen stehen auch schnell zur Verfügung.

http://www.delphipraxis.net/151898-s...ei-reader.html

nahpets 29. Okt 2017 19:39

AW: Große Textdateien spitten
 
Hab' mal ein bisserl rumgespielt, rausgekommen ist dashier:
Delphi-Quellcode:
program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Classes;

const
//  BUFFER_SIZE = 16384; // 1:19
//  BUFFER_SIZE = 65536;  // 1:07
//  BUFFER_SIZE = 65536 * 2; // 1:03
  BUFFER_SIZE = 65536 * 4; // 0:53
//  BUFFER_SIZE = 65536 * 8; // 2:07
  arLow = 0;
  arHigh = 3;
var
  i       : Integer;
  f       : array[arLow..arHigh] of TextFile;
  ff      : TextFile;
  inf_buf : array[1..BUFFER_SIZE] of Byte;
  utf_buf : array[1..BUFFER_SIZE] of Byte;
  sIn     : String;
  sOut    : Array[arLow..arHigh] of String;
  sZeile  : String;
  dtStart : TDateTime;
  dtEnde  : TDateTime;
begin
  dtStart := Now;
  WriteLn('Start : ' + DateTimeToStr(dtStart));
  sIn    := ParamStr(1);

  For i := Low(f) to High(f) do begin
    sOut[i] := ExtractFilePath(ParamStr(0)) + 'Test_' + IntToStr(i) + '.txt';
    AssignFile(F[i],sOut[i]);
    SetTextBuf(F[i],utf_buf, BUFFER_SIZE);
    ReWrite(F[i]);
  end;

  i := 0;
  AssignFile(ff,sIn);
  SetTextBuf(ff,inf_buf,BUFFER_SIZE);
  Reset(ff);
  while not eof(ff) do begin
    ReadLn(ff, sZeile);
    WriteLn(F[i],sZeile);
    inc(i);
    If i > arHigh Then i := arLow;
  end;
  dtEnde := Now;
  WriteLn('Ende : ' + DateTimeToStr(dtEnde));
  WriteLn('Zeit : ' + TimeToStr(dtEnde - dtStart));
  WriteLn('Buffer: ' + IntToStr(Buffer_Size));
  WriteLn('Dateigroessen:');
  WriteLn('Eingabe: ',FileSize(ff) * Buffer_Size,' (',sIn,')');
  CloseFile(ff);
  for i := Low(f) to High(f) do begin
    WriteLn('Ausgabe: ',FileSize(f[i]) * Buffer_Size,' (',sOut[i],')');
    CloseFile(F[i]);
  end;
end.
Hinter der Konstante Buffer_Size steht jeweils, wielange mein Rechner für die Aufteilung einer Datei von 1.250.375.501 Byte benötigt hat.

Eventuell kannst Du damit ja was anfangen.

muhael 29. Okt 2017 20:03

AW: Große Textdateien spitten
 
Hallo Nahpets,

Ich konnte damit die benötigte Zeit von 102 Sekunden auf 25 Sekunden verringern.

Vielen Dank

Start : 29.10.2017 20:59:44
Ende : 29.10.2017 21:00:10
Zeit : 00:00:25
Buffer: 262144
Dateigroessen:
Eingabe: 1535639552 (TestDaten\dbtest_PINAG.txt)
Ausgabe: 383778816 (Test_0.txt)
Ausgabe: 383778816 (Test_1.txt)
Ausgabe: 383778816 (Test_2.txt)
Ausgabe: 383778816 (Test_3.txt)


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:03 Uhr.
Seite 1 von 4  1 23     Letzte »    

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