Process output redirection on a single console line

后端 未结 2 1846
再見小時候
再見小時候 2021-01-14 09:47

I am writing a C# application that can launch third party command line executables and redirect their standard output to a RichTextBox.

I am able to redirect the out

相关标签:
2条回答
  • 2021-01-14 10:09

    If I understand correctly, you are currently seeing progress updates reported to your RichTextBox control as individual lines, while you would like to emulate the behavior of the console window. I.e. to overwrite the previously output line with the new one, rather than keeping the previous line and adding a new one. With that in mind…

    The .NET types, including things like TextReader and the Process class's handling of output, consider a newline to be any of \r, \n, or \r\n. So even a process that is simply using a \r to overwrite the current line would still be interpreted by OutputDataReceived as starting a new line. Given how consistent this behavior is across .NET, your only real option is to avoid using any built-in line-based I/O mechanisms.

    Fortunately, you can get asynchronous reads from the process directly via StandardOutput, instead of having to handle the line-based OutputDataReceived event. For example:

    async Task ConsumeOutput(TextReader reader, Action<string> callback)
    {
        char[] buffer = new char[256];
        int cch;
    
        while ((cch = await reader.ReadAsync(buffer, 0, buffer.Length)) > 0)
        {
            callback(new string(buffer, 0, cch));
        }
    }
    

    You might call it like this:

    // don't "await", but do keep "task" so that at some later time, you can
    // check the result, "await" it, whatever, to determine the outcome.
    Task task = ConsumeOutput(process.StandardOutput, s =>
        {
            richTextBox1.AppendText(s);
        });
    

    Of course, without any modification the above will just do what you are already getting. But reading the output this way will not do any interpretation of the line-break characters. Instead, they will be present in the string s that is passed to the anonymous method handling each read callback. So you can scan that string yourself, looking for lone carriage returns that indicate that you are starting a new line, but should delete the previous line before adding the new text. Be sure to add (or at least skip) all of the text up to the carriage return first, and then delete the last line, before adding the new text.

    0 讨论(0)
  • 2021-01-14 10:32

    This code will fix up raw output and make it as it would appear on the terminal.

     //Deletes all lines that end with only a CR - this emulates the output as it would be seen cmd
    public static string DeleteCRLines( this string Str) {
        Str = Str.Replace( "\r\r\n", "\r\n");
        //Splits at the CRLF. We will end up with 'lines' that are full of CR - the last CR-seperated-line is the one we keep
        var AllLines = new List<string>( Str.Split( new[] {"\r\n"}, StringSplitOptions.None));
        for (int i = 0; i < AllLines.Count; i++){
            var CRLines = AllLines[i].Split('\r');
            AllLines[i] = CRLines[ CRLines.Count() -1];
        }
        return String.Join( Environment.NewLine, AllLines.ToArray());
    }
    
    0 讨论(0)
提交回复
热议问题