Einzelnen Beitrag anzeigen

Benutzerbild von Uwe Raabe
Uwe Raabe

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

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