Как уменьшить потребление памяти PdfPTable со многими ячейками

Я создаю PDF с помощью ITextSharp, который состоит из одной таблицы PDF. К сожалению, для определенного набора данных я получаю исключение "Недостаточно памяти" из-за большого количества создаваемых ячеек PdfPCell (я профилировал использование памяти - у меня есть почти 1/2 миллиона ячеек!)

Есть ли способ уменьшить использование памяти в таком случае? Я пытался очистить в разных точках (после каждого ряда) и полное сжатие

PdfWriter основан на FileStream

Код выглядит примерно так:

Document document = Document();
FileStream stream = new FileStream(fileName,FileMode.Create);                                   
pdfWriter = PdfWriter.GetInstance(document, stream);
document.Open();
PdfPTable table = new PdfPTable(nbColumnToDisplay);
foreach (GridViewRow row in gridView.Rows)
{
    j = 0;
    for (int i = 0; i < gridView.HeaderRow.Cells.Count; i++)
    {
        PdfPCell cell = new PdfPCell( new Phrase( text) );
        table.AddCell(cell);
    }   
}
document.Add(table);
document.Close();

2 ответа

iTextSharp имеет очень крутой интерфейс под названием ILargeElement что PdfPTable реализует. Согласно документации:

/**
* Interface implemented by Element objects that can potentially consume
* a lot of memory. Objects implementing the LargeElement interface can
* be added to a Document more than once. If you have invoked setCompleted(false),
* they will be added partially and the content that was added will be
* removed until you've invoked setCompleted(true);
* @since   iText 2.0.8
*/

Так что все, что вам нужно сделать, это после того, как вы создадите PdfPTable, установить Complete свойство ложно. В вашем внутреннем цикле сделайте некоторую форму счетчика, который время от времени добавляет таблицу и таким образом очищает память. Затем в конце цикла установите Complete к истине и добавить его еще раз.

Ниже приведен пример кода, демонстрирующий это. Без проверки счетчика этот код использует около 500 МБ оперативной памяти на моей машине. При проверке счетчика каждые 1000 элементов он уменьшается до 16 МБ ОЗУ. Вам нужно будет найти свое собственное место для счетчика, и это будет зависеть от того, сколько текста вы добавляете в каждую ячейку в среднем.

string fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "table.pdf");
Document document = new Document();
FileStream stream = new FileStream(fileName, FileMode.Create);
var pdfWriter = PdfWriter.GetInstance(document, stream);
document.Open();

PdfPTable table = new PdfPTable(4);
table.Complete = false;
for (int i = 0; i < 1000000; i++) {
    PdfPCell cell = new PdfPCell(new Phrase(i.ToString()));
    table.AddCell(cell);
    if (i > 0 && i % 1000 == 0) {
        Console.WriteLine(i);
        document.Add(table);
    }
}
table.Complete = true;
document.Add(table);
document.Close();

PdfPTable pdftbale = new PdfPTable(gridview.HeaderRow.Cells.Count);

    foreach (TableCell tabhead in gridview.HeaderRow.Cells)
    {
        PdfPCell pdfcell1 = new PdfPCell(new Phrase(tabhead.Text));
        pdftbale.AddCell(pdfcell1);
    }

    foreach (GridViewRow gd in gridview.Rows)
    {
        foreach (TableCell tab in gd.Cells)
        {
            PdfPCell pdfcell = new PdfPCell(new Phrase(tab.Text));
            pdftbale.AddCell(pdfcell);
        }
    }

    iTextSharp.text.Document pdfDocument = new iTextSharp.text.Document(PageSize.A4, 10f, 10f, 10f, 10f);
    PdfWriter.GetInstance(pdfDocument, new FileStream(Server.MapPath("~/pdf/" + DateTime.Now.ToString("ddMMyyyyhhmmss") + ".pdf"), FileMode.Create));
    pdfDocument.Open();
    pdfDocument.Add(pdftbale);
    pdfDocument.Close();
Другие вопросы по тегам