2011-06-25 89 views
0

我使用此代碼將不同的PDF文件頁面導入到單個文檔。當我導入大文件(200頁或以上)時,我得到一個OutOfMemory異常。我在這裏做錯了什麼?iTextSharp PDF頁面導入內存問題

private bool SaveToFile(string fileName) 
    { 
     try 
     { 
      iTextSharp.text.Document doc; 
      iTextSharp.text.pdf.PdfCopy pdfCpy; 
      string output = fileName; 

      doc = new iTextSharp.text.Document(); 
      pdfCpy = new iTextSharp.text.pdf.PdfCopy(doc, new System.IO.FileStream(output, System.IO.FileMode.Create)); 
      doc.Open(); 

      foreach (DataGridViewRow item in dvSourcePreview.Rows) 
      { 
       string pdfFileName = item.Cells[COL_FILENAME].Value.ToString(); 
       int pdfPageIndex = int.Parse(item.Cells[COL_PAGE_NO].Value.ToString()); 
       pdfPageIndex += 1; 

       iTextSharp.text.pdf.PdfReader reader = new iTextSharp.text.pdf.PdfReader(pdfFileName); 
       int pageCount = reader.NumberOfPages; 

       // set page size for the documents 
       doc.SetPageSize(reader.GetPageSizeWithRotation(1)); 

       iTextSharp.text.pdf.PdfImportedPage page = pdfCpy.GetImportedPage(reader, pdfPageIndex); 
       pdfCpy.AddPage(page); 

       reader.Close(); 
      } 

      doc.Close(); 

      return true; 
     } 
     catch (Exception ex) 
     { 
      return false; 
     } 
    } 

回答

1

您正在爲各個循環中的新PdfReader。這是非常低效的。而且由於每個人都有一個PdfImportedPage,所有這些(可能是冗餘的)實例都不會被GC化。

建議:

  1. ,兩道。首先建立一個文件列表&頁面。其次依次對每個文件進行操作,因此您一次只能有一個「打開」PdfReader。使用PdfCopy.freeReader()當您完成給定的讀者。這幾乎肯定會改變你的頁面添加順序(也許是一件非常糟糕的事情)。
  2. 一通。根據文件名緩存您的PdfReader實例。當你完成時,FreeReader會再次...但在你退出循環之前,你可能無法釋放他們中的任何一個。單獨的緩存可能足以防止內存不足。
  3. 保持您的代碼不變,但在關閉給定的PdfReader實例後請致電freeReader()
1

我還沒遇到iTextSharp的OOM問題。用iTextSharp或其他東西創建PDF文件嗎?您是否可以將問題隔離到單個PDF或一組可能損壞的PDF中?以下是創建10個PDF的示例代碼,每個頁面有1,000個頁面。然後它會創建一個PDF並從這些PDF中隨機抽取1頁500次。在我的機器上運行需要一點時間,但我沒有看到任何內存問題或任何其他問題。 (iText的5.1.1.0)

using System; 
using System.Windows.Forms; 
using System.IO; 
using iTextSharp.text; 
using iTextSharp.text.pdf; 

namespace WindowsFormsApplication1 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 
      //Folder that we will be working in 

      string WorkingFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Big File PDF Test"); 

      //Base name of PDFs that we will be creating 
      string BigFileBase = Path.Combine(WorkingFolder, "BigFile"); 

      //Final combined PDF name 
      string CombinedFile = Path.Combine(WorkingFolder, "Combined.pdf"); 

      //Number of "large" files to create 
      int NumberOfBigFilesToMakes = 10; 

      //Number of pages to put in the files 
      int NumberOfPagesInBigFile = 1000; 

      //Number of pages to insert into combined file 
      int NumberOfPagesToInsertIntoCombinedFile = 500; 

      //Create our test directory 
      if (!Directory.Exists(WorkingFolder)) Directory.CreateDirectory(WorkingFolder); 

      //First step, create a bunch of files with a bunch of pages, hopefully code is self-explanatory 
      for (int FileCount = 1; FileCount <= NumberOfBigFilesToMakes; FileCount++) 
      { 
       using (FileStream FS = new FileStream(BigFileBase + FileCount + ".pdf", FileMode.Create, FileAccess.Write, FileShare.Read)) 
       { 
        using (iTextSharp.text.Document Doc = new iTextSharp.text.Document(PageSize.LETTER)) 
        { 
         using (PdfWriter writer = PdfWriter.GetInstance(Doc, FS)) 
         { 
          Doc.Open(); 
          for (int I = 1; I <= NumberOfPagesInBigFile; I++) 
          { 
           Doc.NewPage(); 
           Doc.Add(new Paragraph("This is file " + FileCount)); 
           Doc.Add(new Paragraph("This is page " + I)); 
          } 
          Doc.Close(); 
         } 
        } 
       } 
      } 

      //Second step, loop around pulling random pages from random files 

      //Create our output file 
      using (FileStream FS = new FileStream(CombinedFile, FileMode.Create, FileAccess.Write, FileShare.Read)) 
      { 
       using (Document Doc = new Document()) 
       { 
        using (PdfCopy pdfCopy = new PdfCopy(Doc, FS)) 
        { 
         Doc.Open(); 

         //Setup some variables to use in the loop below 
         PdfReader reader = null; 
         PdfImportedPage page = null; 
         int RanFileNum = 0; 
         int RanPageNum = 0; 

         //Standard random number generator 
         Random R = new Random(); 

         for (int I = 1; I <= NumberOfPagesToInsertIntoCombinedFile; I++) 
         { 
          //Just to output our current progress 
          Console.WriteLine(I); 

          //Get a random page and file. Remember iText pages are 1-based. 
          RanFileNum = R.Next(1, NumberOfBigFilesToMakes + 1); 
          RanPageNum = R.Next(1, NumberOfPagesInBigFile + 1); 

          //Open the random file 
          reader = new PdfReader(BigFileBase + RanFileNum + ".pdf"); 
          //Set the current page 
          Doc.SetPageSize(reader.GetPageSizeWithRotation(1)); 

          //Grab a random page 
          page = pdfCopy.GetImportedPage(reader, RanPageNum); 
          //Add it to the combined file 
          pdfCopy.AddPage(page); 

          //Clean up 
          reader.Close(); 
         } 

         //Clean up 
         Doc.Close(); 
        } 
       } 
      } 

     } 
    } 
} 
+0

Chris,非常感謝 – kakopappa