2011-06-25 92 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