捕获命令行输出(以字符输出,不必每行等) [英] Capture command line output (by character output, not having to wait per line)

查看:100
本文介绍了捕获命令行输出(以字符输出,不必每行等)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前呈现一个命令行程序的输出到一个文本框。问题是,在一个正常的命令提示符窗口,写入其中一条线具有负载棒之类的话......在这里每隔几秒钟,它输出一个。屏幕....几个点后,将开始一个新的行,然后继续加载,直到它已经完成它的进程。



而不是用下面的代码,的获得这些。出现一个接一个,我OutputDataRecieved正在等待整行地写出来......所以负载酒吧也没用......也就是说,它会等待.............和thennnn它作用于它。



有没有一种方法来跟踪每一个字符输出到屏幕上,而不是什么似乎是每行输出?

  //创建过程
的System.Diagnostics.Process过程=新的System.Diagnostics.Process();

// arguments.ProcessStartInfo包含以下声明:
//的ProcessStartInfo =新的ProcessStartInfo(Cmd.exe中)
// {
//工作目录= executableDirectoryName,
// UseShellExecute =假,
// RedirectStandardInput = TRUE,
// RedirectStandardOutput = TRUE,
// CreateNoWindow = TRUE,
//}
process.StartInfo = arguments.ProcessStartInfo;

//启动过程
StringBuilder的SB =新的StringBuilder();

布尔alreadyThrownExit = FALSE;

//下面的事件似乎只是每行输出来运行,而不是每个字符渲染命令行程序没用
process.OutputDataReceived + =(发件人,E)=>
{
sb.AppendLine(e.Data);
CommandLineHelper.commandLineOutput = sb.ToString();
arguments.DelegateUpdateTextMethod(); (!alreadyThrownExit)

如果
{
如果(process.HasExited)
{
alreadyThrownExit = TRUE;
arguments.DelegateFinishMethod();
process.Close();
}
}
};

的Process.Start();
process.StandardInput.WriteLine(arguments.Command);
process.StandardInput.WriteLine(退出);

process.BeginOutputReadLine();


解决方案

如果你想给定的标准输出的异步处理在每个字符的基础过程中,可以使用 TextReader.ReadAsync()方法。取而代之的是代码,你必须处理 OutputDataReceived 事件,只是做这样的事情:

 的Process.Start(); 

//忽略任务对象,但使编译器高兴
VAR _ = ConsumeReader(process.StandardOutput);

process.StandardInput.WriteLine(arguments.Command);
process.StandardInput.WriteLine(退出);



其中:

 异步任务ConsumeReader(TextReader的读者)
{
的char []缓冲区=新的char [1];

,而((等待read.ReadAsync(缓冲,0,1))大于0)
{
//处理字符...例如:
Console.Write(缓冲[0]);
}
}



另外,你可以只创建一个专门的线程和使用那个叫 TextReader.Read()在一个循环:

 进程。开始(); 

新的Thread(()=>
{
INT CH;

,而((CH = process.StandardOutput.Read())> ; = 0)
{
//处理字符...例如:
Console.Write((char)的CH);
}
})开始();

process.StandardInput.WriteLine(arguments.Command);
process.StandardInput.WriteLine(退出);



IMHO后者是更有效的,因为它并不需要一样多跨线程同步。但前者更类似于你将不得不使用 OutputDataReceived 事件的事件驱动的方式。


I'm currently rendering the output of a command line process into a text box. The problem is that in a normal command prompt window, one of the lines that is written has a load bar kind of thing... where every few seconds it outputs a "." to the screen.... After a few dots, it will start a new line and then continue loading until it has completed its process.

With the following code, instead of getting these "." appear one by one, my OutputDataRecieved is waiting for the whole line to be written out... so the load bar is useless... Ie, it waits for "............." and thennnn it acts upon it.

Is there a way to keep track of every character being output to the screen rather than what seems to be per line outputs?

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

解决方案

If you want asynchronous processing of the stdout of the given process on a per-character basis, you can use the TextReader.ReadAsync() method. Instead of the code you have to handle the OutputDataReceived event, just do something like this:

process.Start();

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

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

where:

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

Alternatively, you could just create a dedicated thread and use that to call TextReader.Read() in a loop:

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" );

IMHO the latter is more efficient, as it doesn't require as much cross-thread synchronization. But the former is more similar to the event-driven approach you would have had with the OutputDataReceived event.

这篇关于捕获命令行输出(以字符输出,不必每行等)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆