【问题标题】:Using itextsharp to merge pdf files within a folder使用 itextsharp 合并文件夹内的 pdf 文件
【发布时间】:2017-09-08 08:27:15
【问题描述】:

我正在尝试使用下面的代码将文件夹中的 pdf 文件合并并输出到一个新文件中,但显然生成的文件似乎已损坏。

public Boolean MergeForm(String destinationFile, String sourceFolder)
    {
        try
        {
            using (MemoryStream stream = new MemoryStream())
            using (Document doc = new Document())
            using (PdfCopy pdf = new PdfCopy(doc, stream))
            {
                doc.Open();

                PdfReader reader = null;
                PdfImportedPage page = null;

                foreach (var file in Directory.GetFiles(sourceFolder))
                {
                    reader = new PdfReader(file);
                    for (int i = 0; i < reader.NumberOfPages; i++)
                    {
                        page = pdf.GetImportedPage(reader, i + 1);
                        pdf.AddPage(page);
                    }

                    pdf.FreeReader(reader);
                    reader.Close();
                }
                using (FileStream streamX = new FileStream(destinationFile, FileMode.Create))
                {
                    stream.WriteTo(streamX);
                }
            }
            return true;
        }
        catch (Exception)
        {
            return false;
        }
    }

谁能发现问题出在哪里?谢谢。

【问题讨论】:

  • 这看起来很像最近的问题using PdfCopy to merge pdf files 的副本。为什么不使用AddDocument() 方法而不是循环遍历不同的页面,一次只添加一页?您使用的是最新版本的 iText 吗?
  • 然而,主要问题是您正在编写文件的那一刻。当您执行stream.WriteTo(streamX) 时,Document 实例尚未关闭。这意味着写入streamX 的PDF 不完整。缺少大量信息(例如交叉引用表、字体、PDF 预告片)。只有当docClose() 发生时,该信息才会添加到stream。在您的情况下,当达到 } 括号 after stream.WriteTo(streamX) 之一时,这会隐式发生。
  • @BrunoLowagie 我正在使用 itextsharp 5.5.12.0。顺便说一句,如何修改代码以使用 AddDocument?我会看看你在这里分享的另一个线程,谢谢。
  • 您是否阅读了我参考的答案中的代码?您会发现类似这样的内容:reader = New PdfReader(file); copy.AddDocument(reader); reader.Close(); 无需遍历页面
  • @BrunoLowagie 哎呀,我在写完答案后才看到你的第二条评论......

标签: c# pdf itext


【解决方案1】:

谁能发现问题出在哪里?

您的主要问题是您在DocumentPdfCopy 完成创建PDF 之前使用了MemoryStream 的内容(在using 块末尾的Dispose 期间)。因此,您保存了一个不完整的 PDF 文件。

这样做应该可行:

    using (MemoryStream stream = new MemoryStream())
    {
        using (Document doc = new Document())
        {
            PdfCopy pdf = new PdfCopy(doc, stream);
            pdf.CloseStream = false;
            doc.Open();

            PdfReader reader = null;
            PdfImportedPage page = null;

            foreach (var file in Directory.GetFiles(sourceFolder))
            {
                reader = new PdfReader(file);
                for (int i = 0; i < reader.NumberOfPages; i++)
                {
                    page = pdf.GetImportedPage(reader, i + 1);
                    pdf.AddPage(page);
                }

                pdf.FreeReader(reader);
                reader.Close();
            }
        }
        using (FileStream streamX = new FileStream(destinationFile, FileMode.Create))
        {
            stream.WriteTo(streamX);
        }
    }

顺便说一句,您在这里也看到我没有将PdfCopy 放入using 块中。这是因为Document 在处理时隐式关闭了PDFCopy。因此,首先处理PdfCopy,然后处理Document(它会再次尝试关闭PdfCopy)是不必要的,并且可能会导致隐藏在此关闭马戏团中发生的其他异常从块内抛出的异常。

此外,我需要添加pdf.CloseStream = false,否则当PdfCopy 关闭时,内存流将被关闭。


说了这么多

  1. 当然,您还应该使用AddDocument,而不是像@Bruno 解释的那样自己迭代文档页面。
  2. 如果您立即写入文件流而不是内存流,您的内存占用将会减少。

【讨论】:

    猜你喜欢
    • 2011-04-24
    • 1970-01-01
    • 1970-01-01
    • 2014-12-14
    • 2017-03-20
    • 1970-01-01
    • 1970-01-01
    • 2021-06-17
    • 1970-01-01
    相关资源
    最近更新 更多