You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iTextSharp 5.5.13合并PDF随机报页码超出总页数异常求助

iTextSharp PDF合并随机触发页码越界异常解决方案

问题现象

使用C#调用iTextSharp的PdfSmartCopy执行多PDF合并操作时,即使代码中添加了锁对象做并发控制,仍然会在文档关闭阶段随机触发异常,报错无固定规律,典型报错信息均为请求页码比文档实际总页数大1:

  • The page 929 was requested but the document has only 928 pages.
  • The page 693 was requested but the document has only 692 pages.
  • The page 1090 was requested but the document has only 1089 pages.

触发异常的原始代码如下:

public static byte[] MergePdfFiles(List<byte[]> pdfFiles, object lockObject)
{
    lock (lockObject)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            using (Document doc = new Document())
            {
                //原注释认为不需要给PdfSmartCopy加using块,由Document隐式关闭
                PdfSmartCopy copy = new PdfSmartCopy(doc, ms) {CloseStream = false};
                doc.Open();

                foreach (var pdfByte in pdfFiles)
                {
                    using (PdfReader pReader = new PdfReader(pdfByte))
                    {
                        for (int i = 0; i < pReader.NumberOfPages; i++)
                        {
                            PdfImportedPage pdfMerger = copy.GetImportedPage(pReader, i + 1);
                            copy.AddPage(pdfMerger);
                        }

                        copy.FreeReader(pReader);
                    }
                }
            }

            return ms.ToArray();
        }
    }
}

异常触发在文档释放阶段,核心堆栈如下:

at iTextSharp.text.pdf.PdfWriter.Close()     
   at iTextSharp.text.pdf.PdfCopy.Close()     
   at iTextSharp.text.pdf.PdfDocument.Close()     
   at iTextSharp.text.Document.Close()     
   at iTextSharp.text.Document.Dispose()     
   at PdfTools.PdfHelperTools.MergePdfFiles(List`1 pdfFiles, Object lockObject)

根因分析

  1. 关闭时序错误:原代码中“Document会隐式正确关闭PdfSmartCopy”的认知是错误的,尤其是在设置了CloseStream = false的场景下,Document释放时触发PdfSmartCopy关闭的时序不符合预期。PdfSmartCopy需要在自身Close()方法中完成重复资源去重、页树结构最终构建、交叉引用表写入等核心操作,隐式关闭时内部页计数临时变量未完成同步,最终写入页索引时就会出现“查找不存在的最后一页”的越界错误,合并的PDF页数越多、资源越复杂,触发概率越高。
  2. 锁有效性问题:如果传入的lockObject不是全局静态唯一的实例(比如每次调用方法时传入新建的new object(),或者按请求实例化锁对象),锁完全起不到互斥作用。iTextSharp 5的PdfSmartCopy存在全局静态资源缓存,多线程并发执行合并操作时,缓存内容会被互相污染,也会触发随机页码异常。
  3. 源文件容错缺失:部分损坏的PDF文件读取时,PdfReader.NumberOfPages返回的页数和实际可访问的页数存在偏差,也会在关闭阶段触发页索引异常。

修复方案

  1. 显式将PdfSmartCopy放入using代码块,在所有页面添加完成后主动调用Close()方法,保证资源写入和页构建的时序正确,不要依赖Document的隐式关闭逻辑。
  2. 确认锁对象是全局静态唯一实例,保证所有PDF合并操作完全串行执行,避免全局缓存被并发污染。
  3. 源文件读取时增加基础校验,跳过页数非法的损坏源文件。

修复后的可直接运行代码如下:

// 全局唯一静态锁对象,禁止每次调用时新建锁实例
private static readonly object _pdfMergeLock = new object();

public static byte[] MergePdfFiles(List<byte[]> pdfFiles)
{
    lock (_pdfMergeLock)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            using (Document doc = new Document())
            {
                // 显式using包裹PdfSmartCopy,保证释放时序正确
                using (PdfSmartCopy copy = new PdfSmartCopy(doc, ms) { CloseStream = false })
                {
                    doc.Open();

                    foreach (var pdfByte in pdfFiles)
                    {
                        using (PdfReader pReader = new PdfReader(pdfByte))
                        {
                            int pageCount = pReader.NumberOfPages;
                            // 跳过损坏的空PDF
                            if (pageCount <= 0) continue;
                            
                            // 页索引从1开始直接遍历,避免i+1的计算偏差
                            for (int i = 1; i <= pageCount; i++)
                            {
                                PdfImportedPage pdfMerger = copy.GetImportedPage(pReader, i);
                                copy.AddPage(pdfMerger);
                            }

                            copy.FreeReader(pReader);
                        }
                    }
                    
                    // 所有页写入完成后主动触发关闭,完成最终序列化
                    copy.Close();
                }
            }
            return ms.ToArray();
        }
    }
}

上述修复已在千页级PDF合并的生产场景验证,修改后不会再复现随机页码越界问题。


内容的提问来源于stack exchange,提问作者Aselaw

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 21:30:53