我正在编写一个C#应用程序,它可以启动第三方命令行可执行文件并将其标准输出重定向到RichTextBox。
我可以使用process.OutputDataReceived事件重定向输出。我有一个队列,我将行推送到,然后我使用计时器定期将所有排队的行转储到RichTextBox。
这适用于某些第三方程序。
问题在于多次向控制台的单行写入的程序。例如:5% - > 10% - > 25%等...(不断改写同一个地方) 我想这是通过不添加换行符来完成的,而是简单地使用回车符回到行的开头并写入前面的字符。
如果OutputDataReceived似乎没有任何方式指示是否应该应用新行,那么我的RichTextBox输出只会在新行上有多个更新。 例如: 5% 10% 25% 等...
有没有办法判断标准输出是在新线还是在同一条线上?
答案 0 :(得分:5)
如果我理解正确,您当前会将进度更新报告给RichTextBox
控件作为单独的行,而您希望模拟控制台窗口的行为。即使用新的输出行覆盖以前的输出行,而不是保留上一行并添加新行。考虑到这一点......
.NET类型,包括TextReader
和Process
类对输出的处理等内容,将换行符视为\r
,\n
或{{ 1}}。因此,即使只是使用\r\n
来覆盖当前行的过程仍然会被\r
解释为开始新行。鉴于这种行为在.NET中的一致性,您唯一真正的选择是避免使用任何内置的基于行的I / O机制。
幸运的是,您可以通过OutputDataReceived
直接从流程中获取异步读取,而不必处理基于行的StandardOutput
事件。例如:
OutputDataReceived
您可以这样称呼它:
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));
}
}
当然,如果没有任何修改,上面的内容就会完成您已经获得的内容。但是以这种方式读取输出将不会对换行符进行任何解释。相反,它们将出现在字符串// 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);
});
中,该字符串将传递给处理每个读取回调的匿名方法。因此,您可以自己扫描该字符串,查找指示您正在开始新行的单独回车符,但应在添加新文本之前删除上一行。确保首先添加(或至少跳过)所有文本到回车符,然后然后删除最后一行,然后再添加新文本。
答案 1 :(得分:1)
此代码将修复原始输出并使其显示在终端上。
//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());
}