【发布时间】:2015-04-10 00:17:48
【问题描述】:
我有一个异步方法,可以从数据库中检索的 XML 创建 PDF 文件。一切正常,但偶尔我会收到 IOException,因为当我在创建 PDF 后尝试清理临时的 .fo 文件时,该文件仍在使用中。
Public Sub FormatObjectToPdf(ByVal intRxNo As Integer, ByVal strSourceFileName As String)
Dim startInfo As New ProcessStartInfo
Dim strPdfFile As String = g_strRootPath & "Paperwork\" & intRxNo & "M.pdf"
' if the PDF file already exists, no need to re-create it
If Not File.Exists(strPdfFile) Then
Try
startInfo.Arguments = "-fo """ & strSourceFileName & """ -pdf """ & strPdfFile & """"
startInfo.FileName = g_strAppPath & "FO.NET\fonet.exe"
startInfo.UseShellExecute = True
startInfo.WindowStyle = ProcessWindowStyle.Hidden
Using proc As Process = Process.Start(startInfo)
proc.WaitForExit()
If proc.HasExited Then
proc.Dispose()
End If
End Using
Catch ex As Exception
Call InsertLog("ErrorLog", "FormatObjectToPdf: " & ex.Message, ex)
MessageBox.Show(ex.Message, "Create PDF", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
End Try
End If
' wait 3 seconds to allow file to be released
System.Threading.Thread.Sleep(3000)
' delete the source FO file when processing is complete
If File.Exists(strSourceFileName) Then
Try
File.Delete(strSourceFileName)
Catch iEx As IOException
Call InsertLog("ErrorLog", "Could not delete file '" & strSourceFileName & "': " & iEx.Message, iEx)
Catch ex As Exception
Call InsertLog("ErrorLog", "Error deleting file '" & strSourceFileName & "': " & ex.Message, ex)
End Try
End If
End Sub
FormatObjectToPdf 方法是从另一个方法AsyncXmlToPdf 中调用的,这实际上是抛出IOException 的地方。我最初认为异常是在FormatObjectToPdf 中,因为这是我要删除.fo 文件的地方,所以我添加了一个Sleep(3000),看看给它几秒钟是否会有所帮助。
这里是AsyncXmlToPdf:
Public Sub AsyncXmlToPdf(ByVal state As Object)
Dim intRxNo = state(0)
Dim flgPrintResult As Boolean = state(1)
Dim strFileName As String = g_strAppPath & intRxNo & ".fo"
Dim strOutput As String
Dim strPdfFile As String = g_strRootPath & "Paperwork\" & intRxNo & "M.pdf"
Try
If File.Exists(strPdfFile) Then
File.Delete(strPdfFile)
End If
If Not File.Exists(strPdfFile) AndAlso Not File.Exists(strFileName) Then
strOutput = XmlToFormatObject(intRxNo, g_strAppPath & "FO.NET\immfo.xsl")
Using writer As StreamWriter = New StreamWriter(strFileName)
writer.Write(strOutput)
End Using
Call FormatObjectToPdf(intRxNo, strFileName)
End If
Catch ex As Exception
Call InsertLog("ErrorLog", "AsyncXmlToPdf: " & ex.Message, ex)
End Try
End Sub
除了strFileName 的声明之外,这两种方法的唯一部分甚至对.fo 文件执行任何操作都在FormatObjectToPdf 中,并且该方法具有用于IOException 的Catch 块。为什么AsyncXmlToPdf 中会捕获到异常??这是实际的错误消息:
3/25/2015 11:15 AM: [IOException] AsyncXmlToPdf: The process cannot access the file 'C:\Users\<username>\AppData\Local\Apps\2.0\1M2D4TCB.REJ\3LH3JZY2.TQC\<clickonce app>\561964.fo' because it is being used by another process.
除了出现此异常时偶尔出现的孤立的.fo 文件外,一切都按预期工作。有人对我如何找出问题所在有任何建议吗?
【问题讨论】:
-
The only part of either method ... that even does anything with the .fo file is in FormatObjectToPdf看起来AsyncXmlToPdf试图在其上打开 StreamWriter。如果它被锁定/使用中,可能会导致异常,但我希望本地捕获会报告它。也许在 File.Exists 测试之后尝试打开它以在新的 Try 块中写入并在新的 Catch 中记录失败。我不确定如何针对要求“建议”的问题发布正确的 SO answer...除非我猜它有效? -
在
AsyncXmlToPdf中,我将StreamWriter包裹在Using块中,所以我认为这将确保在退出Using块后正确释放所有内容。另外,如果文件不存在,我只会打开StreamWriter,以免覆盖它。 -
是的,这似乎不太可能,但请阅读 MSDN 上有关 File.Exists 的 REMARKS 部分 - 是否有其他东西在其他地方使用/创建相同的文件名?
-
我终于能够故意重现该问题。如果我快速连续多次单击启动该过程的按钮,那么我可以让它抛出异常。我想我将不得不禁用该按钮,然后在该过程完成或发生其他事件后重新启用它。感谢@Plutonix 的指导
标签: vb.net pdf asynchronous io