在单个控制台行上处理输出重定向

我正在编写一个C#应用程序,它可以启动第三方命令行可执行文件并将其标准输出重定向到RichTextBox。

我可以使用process.OutputDataReceived事件重定向输出。 我有一个我推送行的队列,然后我使用一个计时器定期将所有排队的行转储到RichTextBox中。

这适用于某些第三方程序。

问题在于多次向控制台的单行写入的程序。 例如:5% – > 10% – > 25%等…(不断重写相同的位置)我想,这是通过不放置换行符来完成的,而是简单地返回到行的开头回车并写回以前的字符。

会发生什么是OutputDataReceived似乎没有任何方式来指示是否应该应用新行,所以我的RichTextBox输出只是在新行上有多个更新。 例如:5%10%25%等…

有没有办法判断标准输出是在新线还是在同一条线上?

如果我理解正确,您当前会将进度更新报告给RichTextBox控件作为单独的行,而您希望模拟控制台窗口的行为。 即用新的输出行覆盖先前的输出行,而不是保留前一行并添加新行。 考虑到这一点…

.NET类型,包括TextReaderProcess类对输出的处理,将换行视为\r\n\r\n 。 因此,即使只是使用\r来覆盖当前行的进程仍然会被OutputDataReceived解释为开始一个新行。 鉴于这种行为在.NET中的一致性,您唯一真正的选择是避免使用任何内置的基于行的I / O机制。

幸运的是,您可以通过StandardOutput直接从进程中获取异步读取,而不必处理基于行的OutputDataReceived事件。 例如:

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

你可以这样称呼它:

 // 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); }); 

当然,如果没有任何修改,上面的内容就会完成您已经获得的内容。 但是以这种方式读取输出将不会对换行符进行任何解释。 相反,它们将出现在传递给处理每个读回调的匿名方法的字符串s中。 因此,您可以自己扫描该字符串,查找指示您正在开始新行的单独回车符,但应在添加新文本之前删除上一行。 在添加新文本之前,请务必先添加(或至少跳过)所有文本到回车符, 然后删除最后一行。

此代码将修复原始输出并使其显示在终端上。

  //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( 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()); }