有没有办法让这更快? MemoryStream与FileStream

时间:2010-12-11 22:47:39

标签: c# itextsharp

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

我列出了下面两种方法 - 原始方法不一定很慢,但我想到为什么要写入和检索文件以获取我需要的输出字符串。我看到了使用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

4 个答案:

答案 0 :(得分:3)

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

验证是否将MemoryStream的初始大小设置为导致大小的某个大值并重新运行代码。

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

答案 1 :(得分:0)

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

另外我认为stream.GetBuffer()会再次返回新的内存,所以请尝试在MemoryStream中使用相同的StreamReader。

看起来您的代码很容易被并行化,因此您可以尝试使用Paralel Extesions或使用TreadPool运行它。

看起来很奇怪,你在文本中将文本写成字节,然后将这个流作为字节读取并转换为文本。是不是可以将文档直接保存为文本?

答案 2 :(得分:0)

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

你当然不能在他们之间施放;你只能向上向上 - 而不是向侧面;可视化:

    Stream
      |

| | FileStream MemoryStream 您可以通过类型检查将MemoryStream简单地转换为Stream,并将Stream转换为MemoryStream;但从来没有FileStream到MemoryStream。这就像说狗是动物,大象是动物,所以我们可以把狗交给大象。

您可以继承MemoryStream并添加一个Name属性(您为其提供值),但FileStream和YourCustomMemoryStream之间仍然没有共性,而FileStream没有实现预先存在的接口来获取名称;因此调用者必须单独显式处理,或使用duck-typing(可能通过动态或反射)。

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

答案 3 :(得分:0)

我知道这很旧了,但是此线程中存在很多错误信息。

这全部与缓冲区大小有关。内存流与文件流相比,内部缓冲区要小得多。较小的缓冲区导致更多的读/写。

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

另一方面,get缓冲区将返回整个分配的缓冲区。因此,如果您只写了1个字节并且缓冲区是4k,则字符串中将有很多垃圾。