【问题标题】:Is there a way to make this faster? MemoryStream vs FileStream有没有办法让它更快?内存流与文件流
【发布时间】:2018-10-03 03:40:37
【问题描述】:

我正在使用 iTextSharp,需要生成数十万个 RTF 文档 - 生成的文件在 5KB 到 500KB 之间。

我在下面列出了 2 种方法 - 原始方法不一定很慢,但我想出了为什么要写入和检索文件以获取我需要的输出字符串。我看到了使用 MemoryStream 的另一种方法,但它实际上减慢了速度。我基本上只需要输出的 RTF 内容,这样我就可以在该 RTF 上运行一些过滤器来清理不必要的格式。带回数据的查询看起来很快。使用原始方法文件生成 1000 个文件(实际上是在创建 2000 个文件)大约需要 15 分钟,与第二种方法相同大约需要 25-30 分钟。我运行的结果文件平均约为 80KB。

第二种方法有问题吗?似乎它应该比第一个更快,而不是更慢。

原来的做法:

RtfWriter2.GetInstance(doc, new FileStream(RTFFilePathName, FileMode.Create));
doc.Open();

   //Add Tables and stuff here

doc.Close(); //It saves a file here to (RTFPathFileName)

StreamReader srRTF = new StreamReader(RTFFilePathName);
string rtfText = srRTF.ReadToEnd();
srRTF.Close();

    //Do additional things with rtfText before writing to my final file

新方法,试图加快速度,但实际上速度只有一半:

  MemoryStream stream = new MemoryStream();
  RtfWriter2.GetInstance(doc, stream);
  doc.Open();

     //Add Tables and stuff here

  doc.Close();

  string rtfText =
  ASCIIEncoding.ASCII.GetString(stream.GetBuffer());
  stream.Close();


      //Do additional things with rtfText before writing to my final file

我在这里找到的第二种方法是: iTextSharp - How to generate a RTF document in the ClipBoard instead of a file

【问题讨论】:

  • 您正在处理的文件有多大?如果它不是很大,那么不,它不会有太大的不同。如果它很大,那么如果它过多地降低系统性能,您可能不想在内存中处理它。
  • 您好,感谢您的回复。我有大约 400,000 个文件需要输出 - 介于 5KB 和 500KB 之间。我正在使用 iTextSharp 从 SQL 查询生成 RTF 内容。
  • 重用内存流。即分配一次并将其用于所有文件,清除其间的内容。
  • 您是否已经对此代码运行了分析器?不要猜测在哪里优化...知道在哪里优化。

标签: c# itextsharp


【解决方案1】:

您的结果流有多大? MemoryStream 在增长的同时会执行大量的内存复制操作,因此对于大型结果,与 FileStream 相比,以小块写入数据可能需要更长的时间。

要验证是否是问题,请将 MemoryStream 的初始大小设置为结果大小附近的某个较大值,然后重新运行代码。

要修复它,您可以最初预增长内存流(如果您知道近似输出)或编写自己的流,在增长时使用不同的方案。同样使用临时文件可能足以满足您的目的。

【讨论】:

    【解决方案2】:

    就像阿列克谢说的那样,这可能是由于事实造成的,你每次都在创建 MemoryStream,并且每次它都会随着它的增长而不断地重新分配内存。尝试仅创建 1 个流并在每次写入之前将其重置为开始。

    我还认为 stream.GetBuffer() 会再次返回新内存,因此请尝试将相同的 StreamReader 与 MemoryStream 一起使用。

    您的代码似乎很容易并行化,因此您可以尝试使用并行扩展或使用 TreadPool 运行它。

    这似乎有点奇怪,您将文本作为字节写入流中,然后将该流作为字节读取并转换为文本。不可以直接将文档保存为文本吗?

    【讨论】:

      【解决方案3】:

      MemoryStream 与文件无关,也没有文件名的概念。基本上,你不能那样做。

      你当然不能在他们之间施放;你只能向上抛向下——不能向侧面抛;可视化:

          Stream
            |
      

      | | 文件流内存流 您可以简单地将 MemoryStream 转换为 Stream,并通过类型检查将 Stream 转换为 MemoryStream;但从不是 FileStream 到 MemoryStream。这就像说狗是动物,大象是动物,所以我们可以把狗扔给大象。

      您可以继承 MemoryStream 并添加一个 Name 属性(您为其提供一个值),但 FileStream 和 YourCustomMemoryStream 之间仍然没有共同点,并且 FileStream 没有实现预先存在的接口来获取 Name ;所以调用者必须明确地分别处理两者,或者使用鸭子类型(可能通过动态或反射)。

      另一个选项(可能更简单)可能是:将数据写入临时文件;从那里使用 FileStream;然后(稍后)删除该文件。

      【讨论】:

        【解决方案4】:

        我知道这很旧,但这个帖子中有很多错误信息。

        这都是关于缓冲区大小的。内存流与文件流相比,内部缓冲区要小得多。较小的缓冲区会导致更多的读\写。

        只需使用文件流或大小约为 80k 的字节数组来初始化您的内存流。关闭文档,将流位置设置为 0 并读取以结束内容。

        附带说明,get buffer 将返回整个分配的缓冲区。所以如果你只写了 1 个字节并且缓冲区是 4k,那么你的字符串中就会有很多垃圾。

        【讨论】:

          猜你喜欢
          • 2014-08-29
          • 2017-03-26
          • 1970-01-01
          • 2012-07-10
          • 2022-06-14
          • 2019-08-06
          • 2020-02-19
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多