Есть ли способ сделать это быстрее?MemoryStream против FileStream - PullRequest
1 голос
/ 12 декабря 2010

Я работаю с iTextSharp, и мне нужно сгенерировать сотни тысяч документов RTF - итоговые файлы имеют размер от 5 КБ до 500 КБ.

Я перечисляю 2 подхода ниже - исходный подход не обязательно был медленным, но я решил, зачем писать и извлекать в / из файл, чтобы получить нужную мне строку вывода. Я видел этот другой подход с использованием MemoryStream, но на самом деле это замедлило процесс. По сути, мне просто нужно выводить содержимое RTF, чтобы я мог запустить несколько фильтров на этом RTF для очистки ненужного форматирования. Запросы, возвращающие данные, выглядят очень быстро. Для создания 1000 файлов (фактически 2000 файлов создаются в процессе) с исходными файлами подхода требуется около 15 минут, то же самое со вторым подходом занимает около 25-30 минут. Полученные файлы в среднем занимают около 80 КБ.

Что-то не так со вторым подходом? Похоже, он должен быть быстрее первого, а не медленнее.

Оригинальный подход:

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 - Как сгенерировать RTF-документ в ClipBoard вместо файла

Ответы [ 4 ]

3 голосов
/ 12 декабря 2010

Насколько велик ваш результирующий поток?MemoryStream выполняет много операций копирования памяти при увеличении, поэтому для больших результатов может потребоваться значительно больше времени для записи данных небольшими порциями по сравнению с FileStream.

Чтобы убедиться, что это проблема, задайте начальный размер MemoryStream для некоторыхбольшое значение вокруг результирующего размера и перезапустите код.

Чтобы исправить это, вы можете предварительно увеличить поток памяти изначально (если вы знаете приблизительный вывод) или написать свой собственный поток, который использует другую схему при увеличении.Также использование временных файлов может быть достаточно для ваших целей.

0 голосов
/ 02 октября 2018

Я знаю, что это старый, но в этой теме много дезинформации.

Это все о размере буфера. Внутренние буферы значительно меньше с потоком памяти против потока файлов. Меньшие буферы вызывают больше чтения \ записи.

Просто инициализируйте ваш поток памяти либо потоком файлов, либо байтовым массивом размером около 80 КБ. Закройте документ, установите позицию потока в 0 и прочитайте, чтобы закончить содержимое.

На заметку о том, что get buffer вернет весь выделенный буфер. Поэтому, если вы записали только 1 байт, а размер буфера равен 4 КБ, в вашей строке будет много мусора.

0 голосов
/ 19 июня 2013

MemoryStream не связан с файлом и не имеет понятия имени файла. По сути, вы не можете этого сделать.

Вы, конечно, не можете разыгрывать между ними; вы можете бросать только вверх, а не вниз; для визуализации:

    Stream
      |

| | FileStream MemoryStream Вы можете преобразовать MemoryStream в Stream тривиально, а Stream - в MemoryStream с помощью проверки типа; но никогда не следует использовать FileStream для MemoryStream. Это все равно, что сказать, что собака - это животное, а слон - это животное, поэтому мы можем привести собаку к слону.

Вы можете создать подкласс MemoryStream и добавить свойство Name (для которого вы указываете значение), но между FileStream и YourCustomMemoryStream не будет общего, и FileStream не реализует ранее существующий интерфейс для получения Name. ; так что вызывающий должен был бы явно обрабатывать оба по отдельности или использовать типизацию утки (возможно, с помощью динамического метода или отражения).

Другой вариант (возможно, более простой) может быть следующим: записать ваши данные во временный файл; используйте FileStream оттуда; затем (позже) удалите файл.

0 голосов
/ 12 декабря 2010

Как сказал Алексей, вероятно, это связано с тем, что вы каждый раз создаете MemoryStream и каждый раз непрерывно перераспределяете память по мере ее роста.Попробуйте создать только 1 поток и сбросить его до начала перед каждой записью.

Также я думаю, что stream.GetBuffer () снова возвращает новую память, поэтому попробуйте использовать тот же StreamReader с вашим MemoryStream.

И этокажется, ваш код может быть легко парализован, поэтому вы можете попробовать запустить его с помощью Paralel Extesions или с помощью TreadPool.

И это кажется немного странным, вы пишете свой текст как байты в потоке, а затем читаете этот поток как байтыпреобразование в текст.Разве нельзя сохранить ваш документ напрямую как текст?

...