iTextSharp Pdf страниц импортировать проблемы с памятью - PullRequest
0 голосов
/ 25 июня 2011

Я использую этот код для импорта различных страниц 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;
        }
    }

Ответы [ 2 ]

1 голос
/ 28 июня 2011

Вы создаете новый PdfReader для каждого прохода. Это ужасно неэффективно. И поскольку у вас есть PdfImportedPage от каждого из них, все эти (вероятно, избыточные) PdfReader экземпляры никогда не GC'ed.

Предложения:

  1. Два прохода. Сначала создайте список файлов и страниц. Во-вторых, работайте с каждым файлом по очереди, так что у вас есть только один PdfReader «открытый» за раз. Используйте PdfCopy.freeReader(), когда вы закончите с данным читателем. Это почти наверняка изменит порядок добавления ваших страниц (возможно, это очень плохо).
  2. Один проход. Кэшируйте ваши PdfReader экземпляры на основе имени файла. FreeReader снова, когда вы закончите ... но вы, вероятно, не сможете освободить ни один из них, пока вы не выпали из цикла. Одного кеширования может быть достаточно, чтобы не допустить исчерпания памяти.
  3. Сохраняйте код как есть, но вызывайте freeReader() после закрытия данного PdfReader экземпляра.
1 голос
/ 28 июня 2011

У меня не было проблем с OOM с iTextSharp.PDF-файлы, созданные с помощью iTextSharp или что-то еще?Можете ли вы выделить проблему в один PDF-файл или в набор PDF-файлов, которые могут быть повреждены?Ниже приведен пример кода, который создает 10 PDF-файлов по 1000 страниц в каждом.Затем он создает еще один файл PDF и случайным образом извлекает 1 страницу из этих файлов 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();
                    }
                }
            }

        }
    }
}
...