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

使用iTextSharp合并PDF时出现空白页插入及页面缺失问题排查

PDF合并工具空白页与页面缺失问题排查

问题描述

我是新手开发者Toru,日常使用C#开发。因业务需求,用PowerShell结合iTextSharp.dll开发了PDF合并工具。测试中发现合并后的PDF存在空白页插入问题:比如合并10页的AAA.pdf与10页的BBB.pdf后,AAA.pdf的第1页和第2页间插入了2-3页空白,还伴随页面缺失情况。尝试用相同PDF文件、增大合并后文件大小等方式复现问题,均未成功。

合并流程

  1. 获取Excel中填写的待合并文件路径数组
  2. 当Excel表格中GrupeNo变量值变化时,进入合并分支
  3. 若输出PDF不存在则创建文件
  4. 检查数组非空则执行合并
  5. 引用相关DLL
  6. 若指定文件夹存在特定文件名,将其追加到输出PDF开头
  7. 获取输出PDF对象
  8. 获取待合并PDF对象并追加到输出PDF
  9. 释放待合并PDF对象
  10. 重复步骤8、9

PowerShell代码

#The 'if' statement for performing PDF merging
if($GrupeNo -ne [int]$worksheet.Cells.Item($r, 5).Text)
{
    #The variable [PdfName] holds the full path of the PDF to be created
    $PdfName = ($UserFullPath + "\"+ $StrFileName + [string]$GrupeNo + ".pdf")

    #If the output destination PDF does not exist, create a new output destination PDF file
    if((Test-Path $PdfName) -eq $false){
        
        New-Item -path $UserFullPath -Name ($StrFileName + [string]$GrupeNo +".pdf")  -ItemType "File"
        Start-Sleep -Milliseconds 3000
    }

    #I am checking whether there is a path for the PDF files to be merged
    if ($ActivePdfFiles.Length -ne 0) 
    {
        
        Set-ItemProperty -path $PdfName -name IsReadOnly -value $false
        $FSO = New-Object System.IO.FileStream($PdfName , [System.IO.FileMode]::OpenOrCreate)
        $BeforPassivePdfFile = New-Object iTextSharp.text.Document 
        $PassivePdfFile = New-Object iTextSharp.text.pdf.PdfSmartCopy($BeforPassivePdfFile,$FSO)
        $BeforPassivePdfFile.Open()
        

        $refFirstPdfPath = Join-Path $Location "cover page" 
        $FirstPdfPath = Join-Path $refFirstPdfPath  ($StrFileName + [string]$GrupeNo +".pdf")
        
        #Processing of the cover page PDF file
        if(($PDFNum -eq 0) -and ((test-path $FirstPdfPath) -eq $true))
        {

            $ActivePdfFile=New-Object iTextSharp.text.pdf.PdfReader($FirstPdfPath) 
            $PassivePdfFile.AddDocument($ActivePdfFile);
            $ActivePdfFile.Close(); 
            $PDFNum = 1
        }
    
        #The iterative loop performing the PDF merging
        for ($i = $NumCheck ; $i -lt $ActivePdfFiles.Count; $i++) 
        {
            if((test-path $ActivePdfFiles[$i]) -eq $false)
            {
                continue
            }
            
            $ActivePdfFile=New-Object iTextSharp.text.pdf.PdfReader($ActivePdfFiles[$i])
            $PassivePdfFile.AddDocument($ActivePdfFile);

            $ActivePdfFile.Close();                    
        }
        $NumCheck = $ActivePdfFiles.Length
    }

   #Releasing the objects
   if ($ActivePdfFile -ne $null) 
   {
       $ActivePdfFile.dispose()
   }

   if ($PassivePdfFile -ne $null) 
   {
       $PassivePdfFile.Dispose();
   }
   if ($FSO -ne $null) 
   {
       $fso.Dispose();
   }
   if ($PhotoPdfFile -ne $null) 
   {
       $PhotoPdfFile.Dispose();
   }
   
   $GrupeNoCheck = $GrupeNo
}

相关环境

  • 使用的DLL:itextsharp.dll(5.5.13.3版本)、BouncyCastle.Crypto.dll
  • 待合并PDF:1-20个,单文件400KB-15MB
  • 输出PDF要求:大小必须小于10MB

排查方向与修复建议

1. 缺失Document对象关闭操作

iTextSharp要求必须调用Document.Close()才能确保所有页面内容写入输出文件,当前代码仅打开$BeforPassivePdfFile但未关闭,直接释放对象会导致文件内容不完整,引发空白页、页面缺失问题。

2. 空文件创建方式错误

用New-Item创建空文件后,直接用FileStream.OpenOrCreate结合PdfSmartCopy操作会有问题——空文件没有合法的PDF结构,PdfSmartCopy无法正确初始化。建议直接通过iTextSharp创建输出文档,替换原有的New-Item逻辑。

3. 对象释放顺序与资源泄漏

  • 循环中仅调用ActivePdfFile.Close()但未及时Dispose(),可能导致资源泄漏;
  • 对象释放顺序错误,应先关闭Document,再依次释放PdfSmartCopy、FileStream,最后处理其他Reader对象。

4. 多余的等待逻辑

Start-Sleep -Milliseconds 3000完全没必要,New-Item是同步操作,执行完成后文件已创建完毕,多余等待无意义。

修改后的关键代码片段

if ($ActivePdfFiles.Length -ne 0) 
{
    Set-ItemProperty -path $PdfName -name IsReadOnly -value $false
    
    # 直接用iTextSharp创建输出文档,避免空文件问题
    $FSO = New-Object System.IO.FileStream($PdfName , [System.IO.FileMode]::Create)
    $BeforPassivePdfFile = New-Object iTextSharp.text.Document 
    $PassivePdfFile = New-Object iTextSharp.text.pdf.PdfSmartCopy($BeforPassivePdfFile,$FSO)
    $BeforPassivePdfFile.Open()

    $refFirstPdfPath = Join-Path $Location "cover page" 
    $FirstPdfPath = Join-Path $refFirstPdfPath  ($StrFileName + [string]$GrupeNo +".pdf")
    
    # 封面处理:及时释放Reader资源
    if(($PDFNum -eq 0) -and (Test-Path $FirstPdfPath))
    {
        $ActivePdfFile=New-Object iTextSharp.text.pdf.PdfReader($FirstPdfPath) 
        $PassivePdfFile.AddDocument($ActivePdfFile);
        $ActivePdfFile.Close();
        $ActivePdfFile.Dispose();
        $PDFNum = 1
    }

    # 合并循环:每次处理完就释放当前Reader
    for ($i = $NumCheck ; $i -lt $ActivePdfFiles.Count; $i++) 
    {
        if(-not (Test-Path $ActivePdfFiles[$i]))
        {
            continue
        }
        
        $ActivePdfFile=New-Object iTextSharp.text.pdf.PdfReader($ActivePdfFiles[$i])
        $PassivePdfFile.AddDocument($ActivePdfFile);

        $ActivePdfFile.Close();
        $ActivePdfFile.Dispose();
    }
    $NumCheck = $ActivePdfFiles.Length

    # 必须关闭Document,确保所有内容写入文件
    $BeforPassivePdfFile.Close();
}

# 调整对象释放顺序:先关闭Document,再释放相关对象
if ($BeforPassivePdfFile -ne $null) 
{
    if($BeforPassivePdfFile.IsOpen()){
        $BeforPassivePdfFile.Close();
    }
    $BeforPassivePdfFile.Dispose();
}

if ($PassivePdfFile -ne $null) 
{
    $PassivePdfFile.Dispose();
}
if ($FSO -ne $null) 
{
    $fso.Dispose();
}

if ($PhotoPdfFile -ne $null) 
{
    $PhotoPdfFile.Dispose();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 11:54:51