如何使用iTextSharp实现DataTable每行数据生成PDF单独一页
问题原因
你的代码存在3个核心问题导致只能输出单页PDF:
- 你在获取到DataTable后就立刻执行了
dt0.Dispose()、ds.Dispose(),后续循环访问dt0.Rows实际是操作已释放的资源,属于隐形逻辑错误 - 你将PDF文档创建、响应输出的逻辑全部放在了For循环内部,第一次循环执行到
Response.End()就会直接终止整个请求处理,后续循环完全不会运行 - 每次循环都新建独立的
Document对象,本质是每次生成一个全新的单页PDF,自然无法合并为多页文件,同时你还做了多余的字节数组转Base64再转字节数组的冗余操作
修复后的代码
Private Sub MySub(Param As String) Try Dim obj As New ReportObjects Dim dt0 As DataTable Dim ds As DataSet = obj.MyStoredProcedure(Param) obj.Dispose() dt0 = ds.Tables(0) ' 把PDF对象创建移到循环外部 Using memoryStream As System.IO.MemoryStream = New System.IO.MemoryStream() Dim document As Document = New Document(PageSize.A4, 1.0F, 1.0F, 1.0F, 1.0F) Dim writer As PdfWriter = PdfWriter.GetInstance(document, memoryStream) document.Open() ' 循环生成每页优惠券 For i As Integer = 0 To dt0.Rows.Count - 1 Dim qrGenerator As QRCodeGenerator = New QRCodeGenerator() Dim qrCode As QRCodeGenerator.QRCode = qrGenerator.CreateQrCode(dt0.Rows(i).Item("VoucherNo"), QRCodeGenerator.ECCLevel.Q) Dim byteImage As Byte() Using bitMap As Bitmap = qrCode.GetGraphic(20) Using ms As MemoryStream = New MemoryStream() bitMap.Save(ms, System.Drawing.Imaging.ImageFormat.Png) byteImage = ms.ToArray() End Using End Using ' 去掉冗余的Base64转码步骤 Dim image As iTextSharp.text.Image = iTextSharp.text.Image.GetInstance(byteImage) ' 非第一页调用NewPage添加新页 If i > 0 Then document.NewPage() document.Add(image) document.Add(New Phrase("Valid From : " & dt0.Rows(i).Item("StartDT").ToString() & " To " & dt0.Rows(i).Item("EndDT").ToString())) Next ' 所有页生成完成后再关闭文档、输出 document.Close() Dim bytes As Byte() = memoryStream.ToArray() ' 释放DataTable相关资源,移到使用完之后 dt0.Dispose() ds.Dispose() Response.Clear() Response.ContentType = "application/pdf" Response.AddHeader("Content-Disposition", "attachment; filename=Vouchers.pdf") Response.Buffer = True Response.Cache.SetCacheability(HttpCacheability.NoCache) Response.BinaryWrite(bytes) Response.End() End Using Catch ex As Exception Throw New Exception(ex.Message) End Try End Sub
核心修改说明
- 调整了资源释放顺序,DataTable、DataSet在所有循环逻辑执行完成后才释放,避免访问已释放对象
- PDF文档实例、输出流的创建移到循环外部,循环内仅处理当前优惠券的二维码生成和内容添加,每处理完一张调用
NewPage()新建下一页 - 所有优惠券页全部生成完成后,再统一将完整的PDF字节流输出到Response,仅调用一次
Response.End() - 删除了无意义的字节数组转Base64再转回字节数组的冗余步骤,减少性能损耗
内容的提问来源于stack exchange,提问作者Arya
相关产品推荐
相关产品推荐

