Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
444 views
in Technique[技术] by (71.8m points)

c# - How to reduce memory consumption of PdfPTable with many cells

I'm creating a PDF using ITextSharp which is composed of a single PdfTable. Unfortunately for a particular data set, I'm getting an Out of memory Exception due to the large number PdfPCells that are created (I've profiled the memory usage - I've got nearly 1/2 a million cells !)

Is there any way to reduce the memory usage in such a case? I've tried flushing at various points (after each row) and full compression

The PdfWriter is based on a FileStream

Code looks a pretty much like this:

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();
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

iTextSharp has a very cool interface called ILargeElement that the PdfPTable implements. According to the documentation:

/**
* 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
*/

So all you need to do is after you create your PdfPTable, set the Complete property to false. In your inner loop do some form of counter that every once in a while adds the table and thus clears the memory. Then at the end of the loop set Complete to true and add it one more time.

Below is sample code that shows this off. Without the counter check this code uses about 500MB of RAM on my machine. With the counter check every 1,000 items it goes down to 16MB of RAM. You'll need to find your own sweet spot for the counter and that will depend on how much text you're adding to each cell on average.

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();

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...