【问题标题】:Should I use a TMemoryStream as an efficient buffer before writing to a file?在写入文件之前,我应该使用 TMemoryStream 作为有效的缓冲区吗?
【发布时间】:2009-04-22 11:59:36
【问题描述】:

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

但是我有一半被遗忘的记忆(可能从 D6 之前的日子开始)在某处阅读 TMemoryStream 效率低下,尤其是在它达到其容量大小之后。我的 Delphi(和 Windows API)技能不足以自己检查 Classes.pas 代码。

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

更让我担心的是,一个相关问题的结论 Using MemoryStream to write out to XML
使用 TMemoryStream,但没有说明原因 - 是因为 TMemoryStream 本身,还是因为 TFileStream 或 I/O 设备驱动程序中有足够的缓冲,或者只是代码的细节有问题。

感谢您的建议
问候,
菲尔W。

【问题讨论】:

  • 嗨,Phil,您最终使用了任何缓冲吗?我可以从谷歌浏览这个页面,想知道缓冲是否会加快我写入文件的速度。我正在将数百万个大整数写入文件并最终尝试了 Ryan 链接到的 TaaWriteBufferFilter,它将 Win XP Pro 上的 30 秒保存时间减少到大约 6 秒!所以我想说,如果你正在做很多小写,我会说绝对值得你花几分钟时间看看用缓冲流包装你的 TFileStream 是否有帮助!谢谢:D

标签: delphi file-io


【解决方案1】:

一个普通的 TFileSram 也做缓冲,这足以优化 I/O。将 MemoryStream 放在前面只会增加开销。

【讨论】:

  • Henk,你确定 TFileStream 是缓冲的吗?随着时间的推移,我在很多地方都读到过 TFileStream 是 not 缓冲的,而 Delphi 的 textfile 实现是缓冲的。我的实践证实 - readln 非常快,而从 TFileStream 读取则不是,尤其是。在循环中读取许多小缓冲区时。缓冲文件流有几个 Delphi 实现(例如 Primoz Gabrijelcic 的 TGpBufferedStream),这也表明本机文件流没有缓冲。
  • 不,Delphi Wrapper TFileStream 不做任何缓冲,但 Win32 流做(尽管有限)缓冲。
  • “让我们保持简单”的方法总是好的。感谢您的建议。
【解决方案2】:

TFileStream 本身不执行缓冲,由操作系统处理,通常足以满足大多数目的。

我的建议是构建一个将数据写入流的方法,然后将 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;

在 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;

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

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;

为 tFilestream 返回 47,为 tJCLBufferedStream 返回 16。没有循环,时间是微不足道的,这就是为什么您需要针对您的数据进行测试......以及您的写作量。

【讨论】:

    【解决方案3】:

    您可以使用 TStringList,并调用 SaveToFile 方法。 TStringList 有一个优点,即当您向其中添加字符串时不会复制内存。

    另一个选项是 Jedi JCL 类 TJclBufferedStream。

    【讨论】:

      【解决方案4】:

      正如其他人所提到的,在 TFileStream 前面添加一个 TMemoryStream 可能不会让你到达你需要到达的地方。

      Julian Bucknall 在“The Delphi Magazine”文章中制作了一组免费软件单元和类,用于向 TStream 对象添加功能。我发现它们在我处理 TStream 对象(尤其是 TFileStream)的大部分过程中都非常有用。

      以下链接来自 google 代码搜索,提供对 aaStrms.pas 文件的直接访问。您将需要其他单位(aaIntDeq.pas、aaIntList.pas、aaRegEx.pas 和 aaStrBld.pas)来使用 aaStrms.pas 文件。这些都是非可视类,所以您需要做的就是包含该单元并实例化该类。

      http://www.google.com/codesearch/p?hl=en#7-hAM65i1Xc/disks/dmag70.zip|alfresco/AAStrms.pas&q=lang:pascal%20aaStrms

      我建议您使用 TaaWriteBufferFilter 类。

      HTH,

      瑞恩

      【讨论】:

      • +1 帮助我将 26MB 二进制文件的 30 秒写入/读取时间减少到大约 5 秒!干杯! :D
      【解决方案5】:

      我会调查是否值得您自己构建一个有限大小的缓冲区。 将少量位写入 TFileStream 很慢(尤其是在存储卷上禁用延迟写入时),因为磁盘驱动程序必须在每个位上定位要写入的扇区。因此,如果您使用一个只有几个扇区大小的缓冲区(安全猜测是 512KB 或 1MB),并在缓冲区已满时写入,它会加快您的工作,而不必担心如何处理巨大的膨胀TMemoryStream。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多