捕获命令行输出(通过字符输出,不必每行等待)

时间:2015-07-17 13:30:24

标签: c#

我目前正在将命令行流程的输出呈现到文本框中。问题是在正常的命令提示符窗口中,写入的一行有一个加载栏类的东西......每隔几秒就输出一个“。”到屏幕....几点后,它将开始一个新的行,然后继续加载,直到它完成它的过程。

使用以下代码,而不是获取这些“。”一个接一个地出现,我的OutputDataRecieved正在等待写出整行...所以加载条没用......就是它等待“.............”和然后它就会对它起作用。

有没有办法跟踪输出到屏幕的每个字符,而不是每行输出似乎是什么?

//Create process
System.Diagnostics.Process process = new System.Diagnostics.Process();

// arguments.ProcessStartInfo contains the following declaration:
// ProcessStartInfo = new ProcessStartInfo( "Cmd.exe" )
// {
//     WorkingDirectory = executableDirectoryName,
//     UseShellExecute = false,
//     RedirectStandardInput = true,
//     RedirectStandardOutput = true,
//     CreateNoWindow = true,
// }
process.StartInfo = arguments.ProcessStartInfo;

//Start the process
StringBuilder sb = new StringBuilder();

bool alreadyThrownExit = false;

// The following event only seems to be run per line output rather than each character rendering the command line process useless
process.OutputDataReceived += ( sender, e ) =>
{
    sb.AppendLine( e.Data );
    CommandLineHelper.commandLineOutput = sb.ToString();
    arguments.DelegateUpdateTextMethod();

    if( !alreadyThrownExit )
    {
        if( process.HasExited )
        { 
            alreadyThrownExit = true;
            arguments.DelegateFinishMethod();
            process.Close();
        }
    }
};

process.Start();
process.StandardInput.WriteLine( arguments.Command );
process.StandardInput.WriteLine( "exit" );

process.BeginOutputReadLine();

1 个答案:

答案 0 :(得分:1)

如果希望基于每个字符异步处理给定进程的stdout,则可以使用TextReader.ReadAsync()方法。而不是你必须处理OutputDataReceived事件的代码,只需执行以下操作:

process.Start();

// Ignore Task object, but make the compiler happy
var _ = ConsumeReader(process.StandardOutput);

process.StandardInput.WriteLine( arguments.Command );
process.StandardInput.WriteLine( "exit" );

其中:

async Task ConsumeReader(TextReader reader)
{
    char[] buffer = new char[1];

    while ((await read.ReadAsync(buffer, 0, 1)) > 0)
    {
        // process character...for example:
        Console.Write(buffer[0]);
    }
}

或者,您可以创建一个专用线程并使用它在循环中调用TextReader.Read()

process.Start();

new Thread(() =>
{
    int ch;

    while ((ch = process.StandardOutput.Read()) >= 0)
    {
        // process character...for example:
        Console.Write((char)ch);
    }
}).Start();

process.StandardInput.WriteLine( arguments.Command );
process.StandardInput.WriteLine( "exit" );

恕我直言后者更有效率,因为它不需要那么多的跨线程同步。但前者更类似于OutputDataReceived事件所采用的事件驱动方法。