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文件——这会导致两个致命问题:
- 最终生成的每个PDF里只填了一行数据,完全没达到“每8条一页”的要求
- 重复创建文件流和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
关键修改说明
- 按组遍历数据:用
Step 8实现每8条数据为一组,避免逐行重复加载模板 - 正确计算总页数:
Math.Ceiling会自动向上取整,比如10条数据会生成2页(8+2) - 组内批量填充:在同一个
PdfStamper实例里填充当前组的所有8个字段,确保一个PDF包含完整的8条数据 - 边界安全判断:添加
dataRowIndex >= dt.Rows.Count的判断,防止处理超出数据范围的索引引发错误
这样修改后,就能正确生成每8条数据一页的PDF表单,不会再出现重复加载模板导致的异常啦。
内容的提问来源于stack exchange,提问作者PyDeveloper
相关产品推荐
相关产品推荐

