【问题标题】:IOException issue with asynchronous PDF creation异步 PDF 创建的 IOException 问题
【发布时间】: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 中,并且该方法具有用于IOExceptionCatch 块。为什么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


【解决方案1】:

The only part of either method ... that even does anything with the .fo file is in FormatObjectToPdf 看来AsyncXmlToPdf 也会尝试在其上打开流写入器。

如果其他一些 BackGroundWorker、Thread 或 Task 也可能在同一组文件上工作,则同一文件可能会在 AsyncXmlToPdfFormatObjectToPdf 中使用。 MSDN 在File.Exists 条目中对此发出警告:

请注意,在您调用 Exists 方法和对文件执行其他操作(例如删除)之间,另一个进程可能会对文件执行某些操作。

在你的情况下,它看起来可能是抛硬币,异常会发生在哪个方法中。

如果意外双击可能会启动同一进程两次,则可能同一文件可能同时在两种方法中使用。您可以添加另一个测试以查看是否可以打开文件进行读写。鉴于该文件不应该存在,您至少可以确定原因。

阻止一组以上作业启动的某种标志可能是最终解决方案。

【讨论】:

  • 按照您的建议,我尝试让进程运行两次以强制多个线程同时尝试创建/处理文件,并找出导致问题的原因。我的解决方案是禁用启动该过程的按钮,直到选择了不同的项目。
猜你喜欢
  • 2019-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-29
  • 2018-12-09
  • 2017-01-09
  • 1970-01-01
相关资源
最近更新 更多