2015-04-10 2 views
2

У меня есть асинхронный метод, который создает файл PDF из XML, извлеченного из базы данных. Все работает отлично, но иногда я получаю IOException, потому что когда я пытаюсь очистить временный файл .fo после создания PDF-файла, файл все еще используется.Проблема с IOException с асинхронным созданием PDF

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 и этот метод имеет Catch блок для IOException. Почему исключение ловят в 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 файла, когда происходит это исключение. У кого-нибудь есть предложения о том, как я могу узнать, где проблема?

+0

'Единственная часть любого из методов ... что даже делает что-либо с файлом .fo в формате FormatObjectToPdf', похоже, что' AsyncXmlToPdf' пытается открыть StreamWriter на нем. Если он заблокирован/используется, что может вызвать исключение, я бы ожидал, что локальный catch сообщит об этом. Возможно, после того, как тест File.Exists попытается открыть его для записи в новом блоке Try и зарегистрировать сбой в новом Catch. Я не уверен, как отправить правильный SO * ответ * на вопрос, требующий «предложений» ... если он не работает, я думаю? – Plutonix

+0

В 'AsyncXmlToPdf', у меня есть' StreamWriter', завернутый в блок 'Using', поэтому я думал, что будет гарантировать, что все будет правильно выпущено после выхода из блока' Using'. Кроме того, я только открываю 'StreamWriter', если файл еще не существует, чтобы не перезаписывать его. –

+0

Да, это не кажется вероятным, но прочитайте раздел REMARKS в MSDN о File.Exists. Может ли что-то еще использовать/создавать одно и то же имя файла в другом месте? – Plutonix

ответ

2

The only part of either method ... that even does anything with the .fo file is in FormatObjectToPdf Похоже, что AsyncXmlToPdf также попытается открыть на нем потоковый блокнот.

Если есть вероятность, что некоторые другие BackGroundWorker, Thread или Task также могут работать с одним и тем же набором файлов, можно было бы использовать один и тот же файл в AsyncXmlToPdf и FormatObjectToPdf. MSDN предупреждает об этом в File.Exists записи:

Имейте в виде, что другой процесс потенциально может сделать что-то с файлом в период между вызовом метода Exists и выполнить другую операцию на файл, например, Delete.

В вашем случае это выглядит как это может быть аа подбрасывания монеты, какой метод Exception будет происходить в.

Если случайно двойной щелчок может запустить такой же процесс в два раза, то возможно, что тот же файл может одновременно использовать оба метода. Вы можете добавить еще один тест, чтобы узнать, можете ли вы открыть файл для ReadWrite. Учитывая, что файл еще не должен существовать, вы, по крайней мере, можете быть несколько уверены в причине.

Может быть окончательным решением может быть некоторый флаг для предотвращения запуска нескольких заданий с момента запуска.

+0

Следуя вашему предложению, я попытался запустить процесс дважды, чтобы заставить несколько потоков пытаться создать/обработать файл одновременно и выяснить, что именно вызывает эту проблему. Мое решение состояло в том, чтобы отключить кнопку, которая запускает процесс, пока не будет выбран другой элемент. –

Смежные вопросы