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

PDF表单分页填充问题求助:按8条结果拆分生成多页PDF

解决PDF表单批量分页生成的问题

我正面临一个PDF表单生成问题:需创建含8个信息填写区域的PDF表单(如图仅展示4个)。数据库查询会返回0至n条结果,要求按每8条拆分并生成对应分页的PDF。我尝试了以下VB代码,但因每次加载新文档导致功能异常,恳请提供解决方案。

原代码

Try 
    Dim sCommand As OleDb.OleDbCommand 
    sCommand = New OleDb.OleDbCommand("SELECT a,b,c Query to fetch n results ", _dbCon) 
    sCommand.CommandTimeout = 0 
    Dim _dbREADER As OleDb.OleDbDataReader 
    _dbREADER = sCommand.ExecuteReader 
    Dim dt As DataTable = New DataTable() 
    dt.Load(_dbREADER) 
    Dim totalPages As Integer = dt.Rows.Count / 8 
    Dim currentPage As Integer = 1 
    Dim rowCounter As Long = 0 
    If dt.Rows.Count > 0 Then 
        For Each row In dt.Rows 
            rowCounter += 1 
            If rowCounter = 8 Then 
                currentPage += 1 
                rowCounter = 0 
            End If 
            _pdfDocumentOutput = System.IO.Path.GetTempPath() & "MailingForm_" & currentPage & ".pdf" 
            SaveFromResources(_pdfDocument, My.Resources.template) 
            Using reader As New PdfReader(_pdfDocument) 
                Using stamper As New PdfStamper(reader, New IO.FileStream(_pdfDocumentOutput, IO.FileMode.Create)) 
                    Dim fontName As String = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts), "SCRIPTIN.ttf") 
                    Dim bf As BaseFont = BaseFont.CreateFont(fontName, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED) 
                    Dim pdfForm As AcroFields = stamper.AcroFields 
                    pdfForm.AddSubstitutionFont(bf) 
                    pdfForm.SetField(rowCounter - 1 & "0", row("Customer")) 
                    'Checks the top radiobutton of the VrPr4 field 
                    pdfForm.SetField(rowCounter - 1 & "1", row("Address")) 
                    pdfForm.SetField(rowCounter - 1 & "2", row("Location")) 
                    stamper.FormFlattening = True 
                End Using 
            End Using 
        Next 
    End If 
    Status.Text = "Store info loaded ! " 
Catch ex As Exception 
    Status.Text = ex.Message 
End Try

问题出在哪?

你的代码现在每处理一行数据就重新加载模板、生成一个新的PDF文件——这会导致两个致命问题:

  1. 最终生成的每个PDF里只填了一行数据,完全没达到“每8条一页”的要求
  2. 重复创建文件流和PDF对象,很容易引发IO异常或者资源泄漏

修正方案:按组批量处理

我们要改成每攒够8条数据就处理一次,只在处理每组数据时加载一次模板,把8条数据都填充到同一个PDF的对应区域里,再生成文件。

下面是修正后的代码:

Try 
    Dim sCommand As OleDb.OleDbCommand 
    ' 记得补充完整你的查询语句,比如加上FROM子句
    sCommand = New OleDb.OleDbCommand("SELECT a,b,c FROM YourTargetTable", _dbCon) 
    sCommand.CommandTimeout = 0 
    Dim _dbREADER As OleDb.OleDbDataReader 
    _dbREADER = sCommand.ExecuteReader 
    Dim dt As DataTable = New DataTable() 
    dt.Load(_dbREADER) 
    
    If dt.Rows.Count > 0 Then 
        ' 用Math.Ceiling确保最后不足8条的数据也能生成一页
        Dim totalPages As Integer = Math.Ceiling(dt.Rows.Count / 8) 
        Dim currentPage As Integer = 1 
        
        ' 按8条为一组遍历数据,Step 8表示每次跳8条
        For groupStartIndex = 0 To dt.Rows.Count - 1 Step 8
            ' 生成当前页的PDF路径
            _pdfDocumentOutput = System.IO.Path.GetTempPath() & "MailingForm_" & currentPage & ".pdf" 
            ' 加载模板到临时文件
            SaveFromResources(_pdfDocument, My.Resources.template) 
            
            ' 只加载一次模板,填充当前组的所有数据
            Using reader As New PdfReader(_pdfDocument) 
                Using stamper As New PdfStamper(reader, New IO.FileStream(_pdfDocumentOutput, IO.FileMode.Create)) 
                    Dim fontName As String = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts), "SCRIPTIN.ttf") 
                    Dim bf As BaseFont = BaseFont.CreateFont(fontName, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED) 
                    Dim pdfForm As AcroFields = stamper.AcroFields 
                    pdfForm.AddSubstitutionFont(bf) 
                    
                    ' 处理当前组内的每一行(最多8条)
                    For groupInnerIndex = 0 To 7
                        ' 计算当前行在DataTable中的索引
                        Dim dataRowIndex = groupStartIndex + groupInnerIndex
                        ' 如果超出数据总数,就停止循环(避免索引越界)
                        If dataRowIndex >= dt.Rows.Count Then Exit For
                        
                        Dim currentRow = dt.Rows(dataRowIndex)
                        ' 填充对应位置的字段:groupInnerIndex是0-7,对应PDF里的8个填写区域
                        pdfForm.SetField(groupInnerIndex & "0", currentRow("Customer").ToString())
                        pdfForm.SetField(groupInnerIndex & "1", currentRow("Address").ToString())
                        pdfForm.SetField(groupInnerIndex & "2", currentRow("Location").ToString())
                    Next
                    
                    stamper.FormFlattening = True 
                End Using 
            End Using 
            
            ' 处理完一组,页码+1
            currentPage += 1
        Next
    End If 
    Status.Text = "Store info loaded ! " 
Catch ex As Exception 
    Status.Text = ex.Message 
End Try

关键修改说明

  1. 按组遍历数据:用Step 8实现每8条数据为一组,避免逐行重复加载模板
  2. 正确计算总页数:Math.Ceiling会自动向上取整,比如10条数据会生成2页(8+2)
  3. 组内批量填充:在同一个PdfStamper实例里填充当前组的所有8个字段,确保一个PDF包含完整的8条数据
  4. 边界安全判断:添加dataRowIndex >= dt.Rows.Count的判断,防止处理超出数据范围的索引引发错误

这样修改后,就能正确生成每8条数据一页的PDF表单,不会再出现重复加载模板导致的异常啦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:53:30