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

Cor*_*rey 3 c# asynchronous redirectstandardoutput

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

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

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

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

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

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

Pet*_*iho 5

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

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

幸运的是,您可以直接通过进程从进程中获取异步读取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));
    }
}
Run Code Online (Sandbox Code Playgroud)

你可以这样称呼它:

// 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);
    });
Run Code Online (Sandbox Code Playgroud)

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