pdfcopy合并pdf失败主因是未调用document.open()或未关闭pdfreader;需绑定已打开document、显式close每个reader、用pdfsmartcopy处理表单/书签/中文字体;大文件须启用延迟读取并及时释放资源。

用 iTextSharp.text.pdf.PdfCopy 合并多个PDF,但输出为空或报错
常见现象是生成的PDF只有几KB、打不开,或者抛出 InvalidOperationException: The document has no pages。根本原因是没调用 document.Open() 就直接往 PdfCopy 写入,或者忘了对每个源PDF调用 reader.Close() 导致资源锁死。
实操要点:
-
PdfCopy必须绑定到一个已Open()的Document实例,不能只 new 一个就开 copy - 每个源
PdfReader要在添加完所有页面后显式Close(),否则后续读取可能失败(尤其在循环处理多个文件时) - 别用
PdfCopy.AddPage()直接传PdfImportedPage—— 它只支持从当前 reader 导入,跨 reader 必须用PdfCopy.AddPage(reader.GetPageN(i)) - 合并含表单或书签的PDF时,
PdfCopy默认丢弃交互元素;需改用PdfSmartCopy(但会慢20%~30%)
合并后中文乱码或字体丢失
iTextSharp 5.x 默认不嵌入中文字体,遇到含中文的PDF,会回退到 Helvetica,导致方块或空白。这不是编码问题,是字体资源未映射。
解决路径:
- 用
BaseFont.CreateFont("C:\Windows\Fonts\simhei.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED)显式加载本地黑体(注意路径权限和字体存在性) - 把该
BaseFont注入到PdfCopy的Writer:先copy.Writer.SetPdfVersion(PdfWriter.PDF_VERSION_1_7),再copy.Writer.AddDirectObject(font) - 更稳妥的做法是:用
PdfSmartCopy替代PdfCopy,它自动尝试复用源PDF中的字体子集(但无法保证100%还原)
iTextSharp 5.5.13+ 迁移后 PdfCopy 报 NullReferenceException
新版 iTextSharp(尤其是 nuget 上带 “LGPL” 后缀的)删掉了部分构造函数重载,new PdfCopy(document, stream) 会因内部 writer 初始化失败而空引用。这不是你代码写错了,是API断层。
绕过方式:
- 降级回
iTextSharp 5.5.12(最后一个稳定版),避免踩坑 - 改用官方推荐替代方案:
iText7的PdfMerger类,但需重写逻辑(merger.Merge(destPdf, sourcePdf)) - 若必须用新iTextSharp,得手动构造
PdfWriter并传入PdfCopy构造函数第二参数:先var writer = PdfWriter.GetInstance(doc, stream),再new PdfCopy(doc, writer)
大文件合并时内存爆满或卡死
一次性读取多个百MB级PDF进内存,PdfReader 会吃光托管堆。不是GC没触发,是iTextSharp内部缓存策略导致的必然结果。
缓解手段:
- 用
new PdfReader(path, null, true)启用“延迟读取”(第三个参数为true),仅解析结构,不加载全部内容到内存 - 逐个打开 → 复制 → 立即
Close()→ 释放reader,别攒一堆 reader 再统一处理 - 避免在 ASP.NET 同步上下文中调用(如 .NET Framework WebForms)—— 改用
Task.Run(() => Merge(...)).Result隔离线程,防请求超时
字体嵌入、跨版本兼容、大文件流式处理——这三个点只要漏掉一个,合并出来的PDF大概率在某个环境里打不开。别信“一键封装”的工具类,每一份PDF的生成源头都可能埋着不同的坑。










