AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Sonstige Fragen zu Delphi 32 Bit, TStringList, Textdatei mit 30Mio. Zeilen
Thema durchsuchen
Ansicht
Themen-Optionen

32 Bit, TStringList, Textdatei mit 30Mio. Zeilen

Ein Thema von hoika · begonnen am 16. Sep 2015 · letzter Beitrag vom 25. Sep 2015
Antwort Antwort
OlafSt

Registriert seit: 2. Mär 2007
Ort: Hamburg
284 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#1

AW: 32 Bit, TStringList, Textdatei mit 30Mio. Zeilen

  Alt 17. Sep 2015, 10:36
Ganz ehrlich: Ich würde den bisherigen Importer eliminieren und das ganze neu (und vor allem sauber) implementieren. Als das damals gebaut wurde, waren 5MB vielleicht große Dateien. Solche Files kann man mit TStringList noch einigermaßen handeln, aber alles darüber wird zur Laufzeit-Qual. Heute sind 5GB große Files kein Thema mehr und in 8 Jahren sind es 5TB große Files. kommt deine LargeStringList damit auch klar, ohne vom Benutzer verlangen zu müssen, er soll n paar RAM-Riegel nachstecken ?

Letztendlich versuchst du, denselben Unsinn (Datei komplett im Speicher) nur auf anderem Weg zu implementieren. Das wird vermutlich scheitern oder bestenfalls eine wenig effiziente Lösung werden. Besser, du investierst deine Zeit in eine Art Parser, der einmal durch die Datei durchgeht, in verschiedenen Listen sich merkt, in welchen Zeilen welcher Satz steht, die A-Sätze schon mal verarbeitet und im zweiten Lauf dann die anderen Sätze dazusortiert. Dann ist es auch fast egal, ob das File 5MB, 5GB oder 5PB groß ist.

Solche Umbau-Arien sind normal, wenn man alte bis sehr alte Projekte bearbeitet. Ich mach das seit Jahren und treffe immer wieder auf solche Stolperfallen.
  Mit Zitat antworten Zitat
Benutzerbild von p80286
p80286

Registriert seit: 28. Apr 2008
Ort: Stolberg (Rhl)
6.659 Beiträge
 
FreePascal / Lazarus
 
#2

AW: 32 Bit, TStringList, Textdatei mit 30Mio. Zeilen

  Alt 17. Sep 2015, 11:14
In "sehr alten" Projekten wird wahrscheinlich keine Stringlist eingesetzt, darum laufen die wohl immer noch

Gruß
K-H
Programme gehorchen nicht Deinen Absichten sondern Deinen Anweisungen
R.E.D retired error detector
  Mit Zitat antworten Zitat
OlafSt

Registriert seit: 2. Mär 2007
Ort: Hamburg
284 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#3

AW: 32 Bit, TStringList, Textdatei mit 30Mio. Zeilen

  Alt 17. Sep 2015, 12:56
Dann ist es aber wohl kein Delphi-Programm TStringList gibt es schon seit D2 (weiter hatte ich keine Lust zu recherchieren). Ich denke eher, das in so einem "sehr alten" Projekt jemand saß, der etwas weiter als 2-3 Jahre gedacht hat
  Mit Zitat antworten Zitat
hoika

Registriert seit: 5. Jul 2006
Ort: Magdeburg
8.277 Beiträge
 
Delphi 10.4 Sydney
 
#4

AW: 32 Bit, TStringList, Textdatei mit 30Mio. Zeilen

  Alt 24. Sep 2015, 14:10
Hallo,
nix gegen den, der das damals so programmiert hat ... (ich war es nicht).

Hier meine Unit.


Heiko


Delphi-Quellcode:
unit LargeStringList;

interface

uses
  Classes;

type
  TLargeStringList = class(TStrings)
    private
      FItems: array of String;

      function GetField(Index: Integer): String;
    public
      property Strings[Index: Integer]: String read GetField; default;

      constructor Create;
      destructor Destroy; override;
      function Count: Integer;
      function Add(const S: String): Integer; override;
      procedure Clear; override;
      procedure LoadFromFile(const DateiName: String); override;
      procedure SaveToFile(const DateiName: String); override;
      procedure AppendToFile(const DateiName: String);
      function Text: String;
      function TextKurz: String;
      function Get(Index: Integer): string; override;
      function GetCount: Integer; override;
      procedure Delete(Index: Integer); override;
      procedure Insert(Index: Integer; const S: String); override;
  end;

implementation

uses
  SysUtils;

{ TLargeStringList }

function TLargeStringList.Add(const S: String): Integer;
var
  iLaenge: Integer;
begin
  iLaenge := Length(FItems);
  SetLength(FItems, iLaenge+1);
  FItems[iLaenge] := S;

  Result := iLaenge;
end;

procedure TLargeStringList.Clear;
begin
  FItems := nil;
end;

function TLargeStringList.Count: Integer;
begin
  Result := Length(FItems);
end;

constructor TLargeStringList.Create;
begin
  inherited ;

  FItems := nil;
end;

destructor TLargeStringList.Destroy;
begin
  FItems := nil;

  inherited;
end;

function TLargeStringList.Get(Index: Integer): string;
begin
  Result := FItems[Index];
end;

function TLargeStringList.GetCount: Integer;
begin
  Result := Length(FItems);
end;

procedure TLargeStringList.Delete(Index: Integer);
begin
  raise Exception.Create('nicht implementiert');
end;

procedure TLargeStringList.Insert(Index: Integer; const S: String);
begin
  raise Exception.Create('nicht implementiert');
end;

function TLargeStringList.GetField(Index: Integer): String;
begin
  Result := FItems[Index];
end;

procedure TLargeStringList.LoadFromFile(const DateiName: String);
var
  TextDatei: TextFile;
  Puffer: array[0..16384] of AnsiChar;
  sZeile: String;
begin
  FItems := nil;

  System.SetTextBuf(TextDatei, Puffer);
  AssignFile(TextDatei, DateiName);
  Reset(TextDatei);
  try
    while not Eof(TextDatei) do
    begin
      ReadLn(TextDatei, sZeile);
      Add(sZeile);
    end;
  finally
    CloseFile(TextDatei);
  end;
end;

procedure TLargeStringList.SaveToFile(const DateiName: String);
var
  TextDatei: TextFile;
  Puffer: array[0..16384] of AnsiChar;
  iZeile: Integer;
  sZeile: String;
begin
  System.SetTextBuf(TextDatei, Puffer);
  AssignFile(TextDatei, DateiName);
  Rewrite(TextDatei);
  try
    for iZeile := 0 to Count-1 do
    begin
      sZeile := Strings[iZeile];
      WriteLn(TextDatei, sZeile);
    end;
  finally
    CloseFile(TextDatei);
  end;
end;

procedure TLargeStringList.AppendToFile(const DateiName: String);
var
  TextDatei: TextFile;
  Puffer: array[0..16384] of AnsiChar;
  iZeile: Integer;
  sZeile: String;
begin
  if FileExists(DateiName) then
  begin
    System.SetTextBuf(TextDatei, Puffer);
    AssignFile(TextDatei, DateiName);
    System.Append(TextDatei);
    try
      for iZeile := 0 to Count-1 do
      begin
        sZeile := Strings[iZeile];
        WriteLn(TextDatei, sZeile);
      end;
    finally
      CloseFile(TextDatei);
    end;
  end
  else
  begin
    SaveToFile(DateiName);
  end;
end;

function TLargeStringList.Text: String;
var
  iZeile: Integer;
  S: String;
begin
  S := '';

  for iZeile := Low(FItems) to High(FItems) do
  begin
    S:= S+#13#10+FItems[iZeile];
  end;

  Result := S;
end;

function TLargeStringList.TextKurz: String;
var
  iZeile: Integer;
  S: String;
begin
  S := '';

  for iZeile := Low(FItems) to High(FItems) do
  begin
    S:= S+#13#10+FItems[iZeile];

    if iZeile>1000 then
    begin
      break;
    end;
  end;

  Result := S;
end;

end.
Heiko
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

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

AW: 32 Bit, TStringList, Textdatei mit 30Mio. Zeilen

  Alt 24. Sep 2015, 14:53
Das hättest du aber einfacher haben können. Deine Implementierung ist weitestgehend identisch mit TStringList, lediglich das LoadFromFile und SaveToFile gehen etwas sparsamer mit dem Speicher um. In der bordeigenen StringList wird die Datei zunächst in einen lokalen Buffer gelesen und dann erst in die StringList übertragen. Das kann bei einer sehr großen Datei in 32-Bit schon mal zu einem Out-Of-Memory führen. Die folgende Implementierung geht da etwas sparsamer mit dem Speicher um.

Es bleibt aber immer noch das Problem, daß alle Zeilen überhaupt in den Speicher passen müssen. Bedenkt man, daß intern mit 2 Byte pro Zeichen zu rechnen ist, die Datei aber womöglich in ANSI oder UTF-8 codiert ist, kann das schon bei einer ca. 1 GB großen Datei zum Problem werden. Bei 30 Millionen Zeilen bleiben da pro Zeile auch nur ca. 30 Zeichen. Ab da sollte man spätestens über eine virtuelle TStrings-Implementation nachdenken.

Delphi-Quellcode:
type
  TMemorySparingStringList = class(TStringList)
  public
    procedure LoadFromStream(Stream: TStream; Encoding: TEncoding); override;
    procedure SaveToStream(Stream: TStream; Encoding: TEncoding); override;
    procedure AppendToFile(const DateiName: String);
  end;

procedure TMemorySparingStringList.AppendToFile(const DateiName: String);
var
  writer: TStreamWriter;
  I: Integer;
begin
  writer := TStreamWriter.Create(DateiName, true);
  try
    for I := 0 to Count - 1 do begin
      writer.WriteLine(Strings[I]);
    end;
  finally
    writer.Free;
  end;
end;

procedure TMemorySparingStringList.LoadFromStream(Stream: TStream; Encoding: TEncoding);
var
  reader: TStreamReader;
begin
  BeginUpdate;
  try
    reader := TStreamReader.Create(Stream, Encoding);
    try
      while not reader.EndOfStream do begin
        Add(reader.ReadLine);
      end;
    finally
      reader.Free;
    end;
  finally
    EndUpdate;
  end;
end;

procedure TMemorySparingStringList.SaveToStream(Stream: TStream; Encoding: TEncoding);
var
  writer: TStreamWriter;
  I: Integer;
begin
  writer := TStreamWriter.Create(Stream, Encoding);
  try
    for I := 0 to Count - 1 do begin
      writer.WriteLine(Strings[I]);
    end;
  finally
    writer.Free;
  end;
end;
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
hoika

Registriert seit: 5. Jul 2006
Ort: Magdeburg
8.277 Beiträge
 
Delphi 10.4 Sydney
 
#6

AW: 32 Bit, TStringList, Textdatei mit 30Mio. Zeilen

  Alt 24. Sep 2015, 16:02
Hallo,
also, ein Stream bringt mir auch sofort den Fehler.

Dass der Algorithmus mal geändert werden muss, ist klar,
aber wir haben hier genug andere Sachen zu tun.
Ich werde eh irgendwann auf 64-Bit umsteigen,
dann ist meine TLargeStringList "open end".

Danke


Heiko
Heiko
  Mit Zitat antworten Zitat
Benutzerbild von Union
Union

Registriert seit: 18. Mär 2004
Ort: Luxembourg
3.492 Beiträge
 
Delphi 7 Enterprise
 
#7

AW: 32 Bit, TStringList, Textdatei mit 30Mio. Zeilen

  Alt 24. Sep 2015, 16:21
Vielleicht könntest Du das Ganze virtualisieren. Die Leseroutine merkt sich nur Anfangsposition und Länge jeder Zeile der Textdatei. Das eigentliche Einlesen der Textzeilen erfolgt dann bei Zugriff. Falls Zeilen mehrfach verarbeitet werden müssen, könnten deren Texte zur Performanceverbesserung in einem Ringspeicher gecached werden.
Ibi fas ubi proxima merces
sudo /Developer/Library/uninstall-devtools --mode=all
  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 18:57 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