Text File Writing Performance in Delphi

delphi, delphi-xe2, file-io, performance

Solution

Use a `TStreamWriter`, which is automatically buffered, and can handle flushing its buffers to the `TFileStream` automatically. It also allows you to choose to append to an existing file if you need to, set character encodings for Unicode support, and lets you set a different buffer size (the default is 1024 bytes, or 1K) in its various overloaded `Create` constructors.

(Note that flushing the `TStreamWriter` only writes the content of the `TStreamBuffer` to the `TFileStream`; it doesn't flush the OS file system buffers, so the file isn't actually written on disk until the `TFileStream` is freed.)

Don't create the StreamWriter every time; just create and open it once, and close it at the end:

function InitLog(const FileName: string): TStreamWriter;
begin
  Result := TStreamWriter.Create(FileName, True);
  Result.AutoFlush := True;         // Flush automatically after write
  Result.NewLine := sLineBreak;     // Use system line breaks
end;

procedure CloseLog(const StreamWriter: TStreamWriter);
begin
  StreamWriter.Free;
end;

procedure TForm1.Button1Click(Sender: TObject);
var 
  tTime : TDateTime;
  iBcl : Integer;
  LogSW: TStreamWriter;
  FileName: TFileName;
begin
  FileName := 'c:\Test.txt';
  LogSW := InitLog(FileName);
  try
    lbl1.Caption := 'Go->' + FileName; 
    lbl1.Refresh;
    tTime := Now;

    For iBcl := 0 to 2000 do
      LogSW.WriteLine(IntToStr(ibcl) + '   ' +  'lkjlkjlkjlkjlkjlkjlkj');

    lbl1.Caption  :=  FormatDateTime('sss:zzz',Now - tTime);
  finally
    CloseLog(LogSW);
  end;
end;

Problem

My program is processing incoming strings (from Telnet, HTTP, etc), and I have to write these to a text file with Delphi XE2 for logging purposes. Sometimes the program may crash and I need to be sure that the remaining strings are not lost so I open/close the file for every incoming string and I have some performance problems. The code below, for example, takes 8 seconds to complete. My code is included below, is there some way to improve the performance? (For the test below simply create a Form with a `Button : Button1`, with `OnClick` event and a `Label : lbl1`). ``` Procedure AddToFile(Source: string; FileName :String); var FText : Text; TmpBuf: array[word] of byte; Begin {$I-} AssignFile(FText, FileName); Append(FText); SetTextBuf(FText, TmpBuf); Writeln(FText, Source); CloseFile(FText); {$I+} end; procedure initF(FileName : string); Var FText : text; begin {$I-} if FileExists(FileName) then DeleteFile(FileName); AssignFile(FText, FileName); ReWrite(FText); CloseFile(FText); {$I+} end; procedure TForm1.Button1Click(Sender: TObject); var tTime : TDateTime; iBcl : Integer; FileName : string; begin FileName := 'c:\Test.txt'; lbl1.Caption := 'Go->' + FileName; lbl1.Refresh; initF(FileName); tTime := Now; For iBcl := 0 to 2000 do AddToFile(IntToStr(ibcl) + ' ' + 'lkjlkjlkjlkjlkjlkjlkj' , FileName); lbl1.Caption := FormatDateTime('sss:zzz',Now-tTime); end; ```

Original source