VB.NET中生成的PDF无法作为邮件附件添加的问题排查
解决PDF生成后作为邮件附件添加时提示文件找不到的问题
我之前也碰到过一模一样的情况:明明PDF已经生成,能打开能查看,但一添加成邮件附件就报FileNotFoundException,路径文件名都对但就是找不到。结合你的代码和报错信息,问题肯定是PDF文件被打印进程占用了——Print()方法执行后,后台的打印服务可能还没完全释放文件句柄,导致邮件程序无法读取这个文件。
先再明确下你的场景:
- 能成功生成PDF到
C:\TEMP\目录 - 可正常打开该PDF文件
- 邮件添加附件时抛出
'System.IO.FileNotFoundException' in mscorlib.dll,提示找不到目标PDF
你的PDF生成代码(可正常运行)
Dim txtVarFile As String Dim txtVarEmail As String = "test@test.com" Dim txtVarPasss As String = "password" Dim txtVarSMTP As String = "smtp.gmail.com" Dim intVarPort As Integer = 587 Dim txtVarDescription As String 'Create Invoice and Save as pdf document txtVarFile = "C:\TEMP\" & strClientNum & "_" & strInvNum & ".pdf" PageSetupDialog1.Document = PrintDocument1 PageSetupDialog1.PrinterSettings.DefaultPageSettings.Landscape = True prtFrmInvoice.PrinterSettings = PageSetupDialog1.PrinterSettings If prtFrmInvoice.PrinterSettings.IsValid Then prtFrmInvoice.PrinterSettings.PrinterName = "Microsoft Print to PDF" prtFrmInvoice.PrintFileName = txtVarFile prtFrmInvoice.PrintAction = Printing.PrintAction.PrintToFile prtFrmInvoice.Print() End If
你的邮件发送代码(添加附件失败)
'Send copy of Invoice per Email Try Dim SmtpServer As New SmtpClient() Dim eMail As New MailMessage() 'Dim attachment As System.Net.Mail.Attachment LogFile.Refresh() SmtpServer.UseDefaultCredentials = False SmtpServer.Credentials = New Net.NetworkCredential(txtVarEmail, txtVarPasss) SmtpServer.Port = intVarPort SmtpServer.EnableSsl = True SmtpServer.Host = txtVarSMTP eMail = New MailMessage() eMail.From = New MailAddress(txtVarEmail) eMail.To.Add(strClientEmail) eMail.Subject = "AltHealth Invoice" eMail.Body = "Please find your latest invoice attached" 'attachment = New System.Net.Mail.Attachment(txtVarFile) 'eMail.Attachments.Add(attachment) eMail.Attachments.Add(New Attachment(txtVarFile)) SmtpServer.Send(eMail) MsgBox("The Invoice has been sent sucessfully via email - File: " & txtVarFile) Catch ex As Exception MsgBox("Send failure: " & ex.ToString()) End Try
解决方案:确保文件生成后完全就绪且未被占用
方案1:等待文件解锁后再发送邮件
写一个辅助函数检测文件是否可以被读写(即未被占用),然后在生成PDF后循环等待,直到文件可用:
' 导入System.IO和System.Threading命名空间 Private Function IsFileAvailable(filePath As String) As Boolean Try ' 尝试以独占方式打开文件,能打开说明未被占用 Using fs As FileStream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None) Return True End Using Catch ex As IOException ' 文件被占用,返回False Return False End Try End Function
然后在prtFrmInvoice.Print()之后添加等待逻辑:
prtFrmInvoice.Print() ' 等待文件解锁 Do While Not IsFileAvailable(txtVarFile) Thread.Sleep(500) ' 每500毫秒检查一次,可根据情况调整 Loop ' 这里再执行邮件发送代码
方案2:手动释放打印对象资源
如果prtFrmInvoice后续不再使用,可以在打印完成后直接释放它的资源,强制关闭文件句柄:
prtFrmInvoice.Print() prtFrmInvoice.Dispose() ' 释放打印窗体/对象的资源,确保文件被解锁
⚠️ 注意:如果之后还要用到prtFrmInvoice,不要调用Dispose(),否则会导致对象不可用。
方案3:检查文件写入是否完成
有时候Print()方法执行完毕,但文件还在后台写入,也会导致读取失败。可以通过检查文件大小是否稳定来判断写入完成:
prtFrmInvoice.Print() Dim prevFileSize As Long = -1 Dim fileInfo As New FileInfo(txtVarFile) Do If fileInfo.Exists Then If fileInfo.Length = prevFileSize Then Exit Do ' 文件大小稳定,说明写入完成 End If prevFileSize = fileInfo.Length End If Thread.Sleep(300) Loop
修改后的完整流程示例
把等待逻辑插入到PDF生成和邮件发送之间,确保文件完全可用:
' 先生成PDF(你的原代码) txtVarFile = "C:\TEMP\" & strClientNum & "_" & strInvNum & ".pdf" PageSetupDialog1.Document = PrintDocument1 PageSetupDialog1.PrinterSettings.DefaultPageSettings.Landscape = True prtFrmInvoice.PrinterSettings = PageSetupDialog1.PrinterSettings If prtFrmInvoice.PrinterSettings.IsValid Then prtFrmInvoice.PrinterSettings.PrinterName = "Microsoft Print to PDF" prtFrmInvoice.PrintFileName = txtVarFile prtFrmInvoice.PrintAction = Printing.PrintAction.PrintToFile prtFrmInvoice.Print() End If ' 添加等待文件可用的逻辑 Do While Not IsFileAvailable(txtVarFile) Thread.Sleep(500) Loop ' 再执行邮件发送(你的原代码) Try Dim SmtpServer As New SmtpClient() Dim eMail As New MailMessage() LogFile.Refresh() SmtpServer.UseDefaultCredentials = False SmtpServer.Credentials = New Net.NetworkCredential(txtVarEmail, txtVarPasss) SmtpServer.Port = intVarPort SmtpServer.EnableSsl = True SmtpServer.Host = txtVarSMTP eMail = New MailMessage() eMail.From = New MailAddress(txtVarEmail) eMail.To.Add(strClientEmail) eMail.Subject = "AltHealth Invoice" eMail.Body = "Please find your latest invoice attached" eMail.Attachments.Add(New Attachment(txtVarFile)) SmtpServer.Send(eMail) MsgBox("The Invoice has been sent sucessfully via email - File: " & txtVarFile) Catch ex As Exception MsgBox("Send failure: " & ex.ToString()) End Try
这个问题的核心就是文件生成后没有完全就绪,被后台进程占用了。用上面的方法确保文件可以被正常读取后,邮件添加附件的问题就能解决了。
内容的提问来源于stack exchange,提问作者AquaAlex
相关产品推荐
相关产品推荐

