简体   繁体   English

文本文件在Delphi中编写性能

[英]Text File Writing performances in Delphi

My soft treat incoming strings (from Telnet or HTTP or...), and I have to write text file with Delphi XE2 for having a trace of incomming treated strings. 我的软处理传入的字符串(来自Telnet或HTTP或......),我必须用Delphi XE2编写文本文件,以获得一些处理过的字符串。 As sometimes the string may crash the program I need to be sure to have the string in my file. 因为有时字符串可能会崩溃程序我需要确保在我的文件中有字符串。 So I open/close the file for every incoming string and I have some performance problems. 所以我打开/关闭每个传入字符串的文件,我有一些性能问题。 Typically (for my code test) 8 seconds for 通常(对于我的代码测试)为8秒

My code is here, is there a way to improve the perfs keeping the function ? 我的代码在这里,有没有办法改善保持功能的性能? (For test just create a Form with a Button : Button1, with OnClick event & a Label : lbl1). (对于测试,只需使用Button创建一个Form:Button1,OnClick事件和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;

Use a TStreamWriter , which is automatically buffered, and can handle flushing its buffers to the TFileStream automatically. 使用自动缓冲的TStreamWriter ,可以自动将其缓冲区刷新到TFileStream 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. 如果需要,它还允许您选择附加到现有文件,为Unicode支持设置字符编码,并允许您在其各种重载的Create构造函数中设置不同的缓冲区大小(默认值为1024字节或1K)。

(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.) (请注意,冲洗TStreamWriter只写的内容TStreamBufferTFileStream ;它不刷新操作系统的文件系统缓存,所以文件实际上并未写入磁盘,直到TFileStream被释放。)

Don't create the StreamWriter every time; 不要每次都创建StreamWriter; 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;

您可以使用FlushFileBuffers函数或通过使用FILE_FLAG_NO_BUFFERINGFILE_FLAG_WRITE_THROUGH标志调用CreateFile函数来打开无缓冲I / O的文件,而不是重新打开文件以保存关键数据(请参阅第一个链接中的“ Remarks部分)。

It seems your problem is that you need to flush the cache after each write so that you won't lose data if your application crashes. 看来你的问题是你需要在每次写入后刷新缓存,以便在应用程序崩溃时不会丢失数据。

Whereas I'm sure the other answers here are excellent, you needn't make such extensive changes to your code. 虽然我确信其他答案非常出色,但您无需对代码进行如此广泛的更改。 All you need to do is call Flush(FText) after each write. 您需要做的就是在每次写入后调用Flush(FText)

const
  // 10 million tests
  NumberOfTests = 1000000;

  // Open and close with each write:        19.250 seconds

  // Open once, and flush after each write:  5.686 seconds

  // Open once, don't flush                  0.439 seconds

var
  FText : Text;
  TmpBuf: array[word] of byte;

procedure initF(FileName : string);
begin
  {$I-}
  if FileExists(FileName) then  DeleteFile(FileName);
  AssignFile(FText, FileName);
  ReWrite(FText);
  SetTextBuf(FText, TmpBuf);
  {$I+}
end;

procedure CloseTheFile;
begin
  CloseFile(FText);
end;

Procedure AddToFile(Source: string);
Begin
  {$I-}
  Writeln(FText, Source);

  // flush the cache after each write so that data will be written
  // even if program crashes.
  flush ( fText );              // <<<====   Flush the Cache after each write

  {$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);

  // put file close in a try/finally block to ensure file is closed
  // even if an exception is raised.
  try

    tTime := Now;
    For iBcl := 0 to NumberOfTests-1 do
      AddToFile(IntToStr(ibcl) + '   ' +  'lkjlkjlkjlkjlkjlkjlkj');
    lbl1.Caption  :=  FormatDateTime('sss:zzz',Now-tTime);

  finally
    CloseTheFile;
  end;
end;

for some reason a simple reading from one text file and writing to text output file I found the TextFile WriteLn is still the fastest way. 由于某种原因,从一个文本文件中简单读取并写入文本输出文件,我发现TextFile WriteLn仍然是最快的方式。

  AssignFile(t,'c:\a\in.csv');
  Reset(t);
  AssignFile(outt,'c:\a\out.csv');
  ReWrite(outt);
  while not eof(t) do
  begin
    Readln(t,x);
    WriteLn(outt, x);   //27 sec, using LogSW.WriteLine(outx) takes 54 sec

// half Gb file took 27 sec with the above code, using TStreamWriter from example provided by Martijn took 54 seconds :o //使用上面的代码,半个Gb文件花了27秒,使用Martijn提供的示例中的TStreamWriter花了54秒:o

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM