【问题标题】:Handle large amounts of output from p.WaitForExit() with RedirectStandardOutput = True使用 RedirectStandardOutput = True 处理来自 p.WaitForExit() 的大量输出
【发布时间】:2012-12-12 11:55:48
【问题描述】:

正如这里所讨论的ProcessStartInfo hanging on "WaitForExit"? Why? - 使用大输出调用 p.WaitForExit() 会填充 OutputStream 并导致死锁,因为进程和输出流相互等待。

以我的代码为例:

Dim p = New Process()
Dim ReturnValue As Boolean = False
p.StartInfo = New ProcessStartInfo(LynxPath, "-dump -nolist -width 1000 " & HtmlBuffer)
p.StartInfo.WorkingDirectory = WorkingRoot
p.StartInfo.UseShellExecute = False
p.StartInfo.RedirectStandardOutput = True
p.StartInfo.RedirectStandardError = True
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
p.StartInfo.CreateNoWindow = True
p.Start()
ReturnValue = p.WaitForExit(5000)

当处理来自 LYNX 的大量输出时,除非我使用上述超时,否则线程会挂起,并且当输出缓冲区满时会修剪输出——这意味着我读取的任何输出都没有完成。

上述问题中发布的 c# 解决方案似乎通过使用进程类上的OutputDataReceived 事件来解决这个问题。然而,我的问题是将 c# 代码转换为 vb.net 3.5,我通过正常的转换路线运行它并吐出:

Using process As New Process()
    process.StartInfo.FileName = filename
    process.StartInfo.Arguments = arguments
    process.StartInfo.UseShellExecute = False
    process.StartInfo.RedirectStandardOutput = True
    process.StartInfo.RedirectStandardError = True

    Dim output As New StringBuilder()
    Dim [error] As New StringBuilder()

    Using outputWaitHandle As New AutoResetEvent(False)
        Using errorWaitHandle As New AutoResetEvent(False)
            process.OutputDataReceived += Function(sender, e) 
            If e.Data Is Nothing Then
                outputWaitHandle.[Set]()
            Else
                output.AppendLine(e.Data)
            End If

End Function
            process.ErrorDataReceived += Function(sender, e) 
            If e.Data Is Nothing Then
                errorWaitHandle.[Set]()
            Else
                [error].AppendLine(e.Data)
            End If

End Function

            process.Start()

            process.BeginOutputReadLine()
            process.BeginErrorReadLine()

                ' Process completed. Check process.ExitCode here.
            If process.WaitForExit(timeout) AndAlso outputWaitHandle.WaitOne(timeout) AndAlso errorWaitHandle.WaitOne(timeout) Then
                ' Timed out.
            Else
            End If
        End Using
    End Using
End Using

然而,Visual Studio 2008 将函数声明标记为无效语法(我认为像这样的内联方法是在 4.5 及更高版本中?),如何在 3.5 中使用这个示例 - 无法完全理解它。

编辑:刚刚找到了这个链接:http://msdn.microsoft.com/en-us/library/system.diagnostics.process.outputdatareceived.aspx - 现在想弄清楚

【问题讨论】:

  • 您可能对this post 感兴趣,它解释了如何使用异步任务而不是笨拙的数据接收事件来处理流程

标签: c# .net vb.net process .net-3.5


【解决方案1】:

这就是我们最终想出的,它接受一个 html 字符串,将其写入一个文件,然后用 lynx 打开它,然后使用事件句柄(处理大量输出)捕获 lynx 输出并填充一个纯文本字符串:

Function ConvertHtmlToPlainText(ByVal HtmlString As String) As String

    ' Define FileBuffer Path
    Dim HtmlBuffer As String = WorkingRoot & "HtmlBuffer.html"

    ' Delete any old buffer files
    Try
        If File.Exists(HtmlBuffer) = True Then
            File.Delete(HtmlBuffer)
        End If
    Catch ex As Exception
        Return "Error: Deleting old buffer file: " & ex.Message
    End Try

    ' Write the HTML to the buffer file
    Try
        File.WriteAllText(WorkingRoot & "HtmlBuffer.html", HtmlString)
    Catch ex As Exception
        Return "Error: Writing new buffer file: " & ex.Message
    End Try

    ' Check the file was written OK
    If File.Exists(HtmlBuffer) = False Then
        Return "Error: HTML Buffer file was not written successfully."
    End If

    If File.Exists(LynxPath) = False Then
        Return "Error: Lynx.exe could not be found in path: " & LynxPath
    End If

    ' Read the buffer file with Lynx and capture plain text output
    Try
        LynxOutput = ""
        LynxOutputLineCount = 0
        Dim LynxProcess As New Process()
        LynxProcess.StartInfo = New ProcessStartInfo(LynxPath, "-dump -nolist -width 1000 " & HtmlBuffer)
        LynxProcess.StartInfo.UseShellExecute = False
        LynxProcess.StartInfo.RedirectStandardOutput = True
        LynxProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
        LynxProcess.StartInfo.CreateNoWindow = True
        AddHandler LynxProcess.OutputDataReceived, AddressOf LynxOutputHandle
        LynxProcess.StartInfo.RedirectStandardInput = True
        LynxProcess.Start()
        LynxProcess.BeginOutputReadLine()
        LynxProcess.WaitForExit()
        LynxProcess.Close()

        ' Return the rendered Text
        Return TrimEachLine(LynxOutput.Replace(vbLf & vbLf, vbLf))

    Catch ex As Exception
        Return "Error: Error running LYNX to parse the buffer: " & ex.Message
    End Try
End Function

Private Sub LynxOutputHandle(ByVal sendingProcess As Object, ByVal outLine As DataReceivedEventArgs)
    LynxOutputLineCount = LynxOutputLineCount + 1
    LynxOutput = LynxOutput & outLine.Data & vbLf
End Sub

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-01
    • 1970-01-01
    • 2010-11-13
    • 1970-01-01
    • 1970-01-01
    • 2011-11-12
    • 2015-03-28
    • 1970-01-01
    相关资源
    最近更新 更多