C# 进程换行,某些输出不显示

C# 进程换行,某些输出不显示,c#,process,C#,Process,我有一个小型包装应用程序,为现有控制台应用程序提供GUI。我正在使用ProcessStartInfo和Process类绑定到.exe,然后使用BeginErrorReadLine()和BeginOutputReadLine()将任何消息重定向到新的GUI中。除了控制台调用console.Write()而不是console.WriteLine(),在这种情况下,传递给Write的文本根本不显示之外,其他一切都正常。我认为问题是因为WriteLine函数在文本后插入了换行符,而Write方法没有。有

我有一个小型包装应用程序,为现有控制台应用程序提供GUI。我正在使用
ProcessStartInfo
Process
类绑定到.exe,然后使用
BeginErrorReadLine()
BeginOutputReadLine()
将任何消息重定向到新的GUI中。除了控制台调用
console.Write()
而不是
console.WriteLine()
,在这种情况下,传递给
Write
的文本根本不显示之外,其他一切都正常。我认为问题是因为
WriteLine
函数在文本后插入了换行符,而
Write
方法没有。有什么办法可以避免这种情况吗?我无法在原始命令行程序中将其从
Write
更改为
WriteLine
,因为
Write
用于提示输入

相关代码:

var startInfo = new ProcessStartInfo(ServerFile);
startInfo.RedirectStandardInput = true;
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardOutput = true;

ServerProc = new Process();
ServerProc.StartInfo = startInfo;
ServerProc.EnableRaisingEvents = true;
ServerProc.ErrorDataReceived += new DataReceivedEventHandler(ServerProc_ErrorDataReceived);
ServerProc.OutputDataReceived += new DataReceivedEventHandler(ServerProc_OutputDataReceived);

private void ServerProc_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
    Dispatcher.Invoke(new Action(() =>
    {
        ConsoleTextBlock.Text += e.Data + "\r\n";
        ConsoleScroll.ScrollToEnd();
    }));
}

private void ServerProc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
    Dispatcher.Invoke(new Action(() =>
    {
        ConsoleTextBlock.Text += e.Data + "\r\n";
        ConsoleScroll.ScrollToEnd();
    }));
}

您遇到的问题是,设置
进程
类是为了方便地对进程的输出进行面向行的基于事件的处理。如果需要在输出部分行时读取这些行,则不能使用此功能

然而,如果您需要对输出进行比面向行的工具更细粒度的控制,那么
过程
类确实为您提供了所需的工具。如果重定向输出,则
Process.StandardOutput
是一个
StreamReader
,您可以使用整个
StreamReader
API,而不必强制读取整行

例如,以下是标准输出的逐字符读取:

var start = DateTime.Now;
int n;
while ((n = ServerProc.StandardOutput.Read()) != -1)
{
    var c = (char)n;
    var delta = (DateTime.Now - start).TotalMilliseconds;
    Console.WriteLine("c = {0} (0x{1:X}) delta = {2}",
        char.IsWhiteSpace(c) ? '*' : c, n, delta);
}
如果我们在另一个生成此输出的控制台程序上运行它:

Console.Write("abc");
Thread.Sleep(1000);
Console.WriteLine("def");
c = a (0x61) delta = 44.0025
c = b (0x62) delta = 44.0025
c = c (0x63) delta = 44.0025
c = d (0x64) delta = 1109.0634
c = e (0x65) delta = 1110.0635
c = f (0x66) delta = 1110.0635
c = * (0xD) delta = 1110.0635
c = * (0xA) delta = 1110.0635
它产生以下输出:

Console.Write("abc");
Thread.Sleep(1000);
Console.WriteLine("def");
c = a (0x61) delta = 44.0025
c = b (0x62) delta = 44.0025
c = c (0x63) delta = 44.0025
c = d (0x64) delta = 1109.0634
c = e (0x65) delta = 1110.0635
c = f (0x66) delta = 1110.0635
c = * (0xD) delta = 1110.0635
c = * (0xA) delta = 1110.0635
这表明
“abc”
是在行的其余部分前一秒读取的

但是,如果您喜欢
进程
已经提供的面向事件的I/O,则这并不方便。您可以:

  • 使用异步
    API
  • 使用执行阻塞读取的线程
甚至可以推出满足您需求的基于事件的I/O

您正在编写一个程序,该程序正在解析另一个程序的面向字符的输出,因此如果没有完整的行,您将需要某种类型的超时来表示“我现在确信该程序已经完成了当前的输出”。这可能是容易的,也可能是困难的,这取决于输出的可预测性。例如,您可能能够识别以
“?”
结尾的提示。这取决于你的情况


关键是,如果您想要的不是面向行的I/O,那么必须使用
StandardOutput
StandardError
StreamReader
属性。

Sladkey据我所知,使用异步和同步读取之间的问题是,我必须手动调用写入函数,而不是基于事件。这是正确的吗?最好的解决方案是类似计时器的东西吗?解析程序的输出需要编写一个解析器,最好是一个简单的解析器。将解析器作为线程编写是最容易的,否则您将需要一个状态机。如果输出是确定性的,您甚至不需要任何计时器。这不是一项琐碎的任务,解决方案取决于您的需求和应用程序。设计需要与解析线程协作,这可能是使用事件最容易做到的。除此之外,还有许多实用的方法!