iTextSharp Pdf页面导入内存问题

本文关键字:内存 问题 导入 Pdf iTextSharp | 更新日期: 2023-09-27 18:00:27

我使用此代码将不同的pdf文件页面导入到单个文档中。当我导入大文件(200页或以上)时,会出现OutOfMemory异常。我在这里做错什么了吗?

    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;
        }
    }

iTextSharp Pdf页面导入内存问题

每次通过都要创建一个新的PdfReader。这效率非常低。因为每个实例都有一个PdfImportedPage,所以所有这些(可能是冗余的)PdfReader实例永远不会是GC’ed。

建议:

  1. 两次传球。首先建立一个文件列表&页面。第二步依次对每个文件进行操作,因此一次只能"打开"一个PdfReader。使用完给定的阅读器后,请使用PdfCopy.freeReader()。这几乎肯定会改变页面的添加顺序(可能是一件非常糟糕的事情)
  2. 一次通过。根据文件名缓存PdfReader实例。完成后再次使用FreeReader。。。但在退出循环之前,你可能无法释放其中的任何一个。仅缓存就足以防止内存不足
  3. 保持代码原样,但在关闭给定的PdfReader实例后调用freeReader()

我没有遇到iTextSharp的OOM问题。PDF是用iTextSharp还是其他东西创建的?您能否将问题隔离为单个PDF或一组可能已损坏的PDF?下面是创建10个PDF的示例代码,每个PDF有1000页。然后,它再创建一个PDF,并从这些PDF中随机抽取一页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();
                    }
                }
            }
        }
    }
}