在写入文件之前,我应该使用TMemoryStream作为有效的缓冲区吗?

Phi*_*ilW 4 delphi file-io

我正在使用D6 Professional,需要从内存中已有的许多小字符串创建特定格式的文本文件.出于性能原因,我正在考虑使用TMemoryStream来整理文件数据,然后通过TFileStream一次性将其写入磁盘.

但是我有一半被遗忘的记忆(可能是在D6之前的日子里)读取TMemoryStream效率低下的地方,特别是在它达到容量大小之后.我的Delphi(和Windows API)技能不足以检查自己的Classes.pas代码.

(OFFTOPIC)特别是这样的代码:( Classes.pas的第5152行):
NewCapacity:=(NewCapacity +(MemoryDe​​lta - 1))而不是(MemoryDe​​lta - 1);
(/无关)

添加到我的担心是,相关问题的结论, 使用的MemoryStream写出来,希望XML
使用内存流,但没有说为什么-无论是由于内存流本身,还是因为在TFileStream的或我足够的缓冲/ O设备驱动程序,或只是相关代码的细节.

感谢任何建议
问候,
PhilW.

Hen*_*man 8

普通的TFileStram也可以进行缓冲,这足以优化I/O. 将MemoryStream放在前面只会增加开销.

  • Henk,你知道TFileStream是否已经缓冲了吗?随着时间的推移,我已经在许多地方读过,TFileStream不是**,而Delphi的文本文件的实现是.我的做法证实 - readln非常快,而从TFileStream读取则不是,尤其是 在循环中读取许多小缓冲区时.有一些缓冲文件流的Delphi实现(例如Primoz Gabrijelcic的TGpBufferedStream),它也向我提出本机文件流没有缓冲. (3认同)

ska*_*adt 8

TFileStream本身不执行由OS处理的缓冲,并且通常足以用于大多数目的.

我的建议是构建一个方法将数据写入流,然后将TSTream参数传递给此方法.这样,您可以轻松地测试不同的选项,而不会影响您的程序.

例如:

Procedure TForm1.StreamMyObjects(aStream : tStream);
begin
  aStream.Write( MyString[1], Length( MyString ) * SizeOf( Char ));
  aStream.Write( CRLF, Length( CRLF ) * SizeOf( Char ));
  aStream.Write( MyOtherString[1], Length( MyOtherString ) * SizeOf( Char ));
  aStream.Write( CRLF, Length( CRLF ) * SizeOf( Char ));
end;
Run Code Online (Sandbox Code Playgroud)

在JCL中,如前所述,有一个TJclBufferedStream,然后您可以测试它是否有任何性能优势,这将根据您的写作和您的写作量而有所不同.例如,以下将测试TFileStream和tJCLBufferedStream以查看差异(是的,我知道我错过了TRY/FINALLY):

var
  fstm : tFileSTream;
  fBufStm : tJCLBufferedStream;
  iTicks : Cardinal;
  fModes : word; // for SO formatting.
begin
  fModes := fmOpenReadWrite or fmCreate or fmShareExclusive;

  iTicks := GetTickCount;
  fstm := tFilestream.create('test1.txt',fModes);
  StreamMyObjects( fStm );
  fstm.free;
  ShowMessage('TEST1='+IntToSTr(GetTickCount-iTicks));

  iTicks := GetTickCount;
  fstm := tFilestream.create('test2.txt',fModes);
  fBufStm := tJclBufferedStream.create( fStm );
  StreamMyObjects( fBufStm );
  fBufStm.free;
  fstm.free;
  ShowMessage('TEST2='+IntToSTr(GetTickCount-iTicks));
end;
Run Code Online (Sandbox Code Playgroud)

在我的测试中,以下例程:

procedure TForm1.StreamMyObjects(aSTream: tStream);
var
  St : string;
  ix : integer;
begin
  for ix := 0 to 10000 do
    begin
      St := 'This is a string which is written to a stream. ' + IntToStr(ix);
      aStream.Write(st[1], Length(st) * SizeOf(Char) );
    end;
end;
Run Code Online (Sandbox Code Playgroud)

tFilestream返回47,tJCLBufferedStream返回16.没有循环,时间是微不足道的,这就是为什么你需要测试你的数据...以及你的写作多少.