使用Process实时控制台输出重定向

时间:2010-02-25 06:33:13

标签: c# process console-redirect

我正在使用VBOXMANAGE来“导出”来宾计算机。 VBOXManage是一个控制台应用程序,可以控制来宾主机的来宾行为。由于export命令是一个很长的进程,它会返回进程更新,如下所示:

0%... 10%... 20%... 30%... 100%

我正在编写一个C#应用程序,它将使用Process调用VBOXManage。这是我的代码:

Process VBOXProc = new Process();

VBOXProc.StartInfo.FileName = VBOXMANAGE;
VBOXProc.StartInfo.Arguments = Arguments;
VBOXProc.StartInfo.UseShellExecute = false;
VBOXProc.StartInfo.CreateNoWindow = true;
VBOXProc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
VBOXProc.StartInfo.RedirectStandardError = true;
VBOXProc.StartInfo.RedirectStandardOutput = true;

VBOXProc.OutputDataReceived += new DataReceivedEventHandler(VBOXProc_OutputDataReceived);
VBOXProc.ErrorDataReceived += new DataReceivedEventHandler(VBOXProc_ErrorDataReceived);

VBOXProc.EnableRaisingEvents = true;

VBOXProc.Start();
VBOXProc.BeginOutputReadLine();
VBOXProc.BeginErrorReadLine();

VBOXProc.WaitForExit();

这很好,除了按LINE读取输出。这意味着该过程更新“ 0%... 10%...... 20%...... 30%...... 100%“仅在实际流程完成后显示。

有没有办法实时捕获控制台输出?

谢谢!

4 个答案:

答案 0 :(得分:6)

您可以使用所有标准Stream方法直接从StanadardOutput / Error读取进程,只需确保将StartInfo.Redirectxxx设置为true。

var p = new Process()
p.StartInfo.UseShellExecute = false;  //not sure if this is absolutely required
p.StartInfo.RedirectStandardOuput = true;
....

do
{
  Thread.Sleep(nnn);
  Console.Out.Write(p.StandardOutput.ReadToEnd());
}
while (!p.HasExited);
//catch any leftovers in redirected stdout
Console.Out.Write(p.StandardOutput.ReadToEnd());

以上内容将子进程的输出回显给您的应用程序标准输出。

您可以使用p.StandardOutput.Read(char [],int,int)读取特定大小的块,或使用p.StadardOutput.BaseStream.BeginRead(...)读取异步读取。

所有相同的方法都适用于StandardError。

在循环中休眠会释放处理器以执行其他任务,并允许一些数据在缓冲区中累积。如果睡眠周期太长并且缓冲区溢出,则执行过程中的某些输出将丢失。如果睡眠时间太短,则会花费很多CPU周期来读取和清空缓冲区。

答案 1 :(得分:6)

这对我有用

        process.StartInfo.CreateNoWindow = true;
        process.StartInfo.ErrorDialog = false;
        process.StartInfo.RedirectStandardError = true;
        process.StartInfo.RedirectStandardOutput = true;
        process.StartInfo.UseShellExecute = false;

        process.ErrorDataReceived += (sendingProcess, errorLine) => error.AppendLine(errorLine.Data);
        process.OutputDataReceived += (sendingProcess, dataLine) => SetMessage(dataLine.Data);

        process.Start();
        process.BeginErrorReadLine();
        process.BeginOutputReadLine();

        process.WaitForExit();

error.AppendLine()和SetMessage()是我的方法。

答案 2 :(得分:0)

尝试重定向标准输入并将AutoFlush应用于StandardInput。接下来使用StreamReader读取流。

Process proces;
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "test.exe";
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardInput = true;

proces = Process.Start(psi);
proces.StandardInput.AutoFlush = true;

答案 3 :(得分:0)

对不起任何错误,我是巴西人,并使用Google翻译来撰写此文。

巧合的是,我也在做一个与Virtualbox的VBoxManage配合使用的程序。在我的情况下,除其他外,我想要转换虚拟磁盘。它也延迟了,进展的百分比也是

我设法通过创建运行程序的意愿流程,并使用用户类'Dean North`和其他类似的question来实现这一目的。使用线程运行VBoxManage非常重要,否则无法处理获取的文本或查看进度。

Otextoémuitogrande pra eu adicionarquatroespaçosantesde cada linha e repassar。

这些类取代了Process系统类。无需对代码进行任何更改,只需添加arquivo.cs,其中包含用户Dean North而不是Process p = new Process()使用FixedProcess p = new FixedProcess ()

传递的文字

之后是我的代码:

private void BotaoParaTestes_Click(object sender, EventArgs e)
{
    string linha = @"clonehd " +
        "\"Z:\\Máquinas Virtuais\\Teste.vdi\" " +
        "\"C:\\Temp\\teste.vdi\" " +
        "--format VDI --variant Standard";

    Thread tarefa = new Thread(Executar);
    tarefa.Start(linha);
}
private void Executar(object Linha)
{
    FixedProcess fp = new FixedProcess ();
    fp.StartInfo.FileName = ItensEstaticos.VBox;
    fp.StartInfo.Arguments = Linha.ToString();
    fp.StartInfo.CreateNoWindow = true;
    fp.StartInfo.ErrorDialog = false;
    fp.StartInfo.RedirectStandardError = true;
    fp.StartInfo.RedirectStandardOutput = true;
    fp.StartInfo.UseShellExecute = false;
    fp.ErrorDataReceived += (sendingProcess, errorLine) => Escrita(errorLine.Data);
    fp.OutputDataReceived += (sendingProcess, dataLine) => Escrita(dataLine.Data);
    fp.Start();
    fp.BeginErrorReadLine();
    fp.BeginOutputReadLine();

    fp.WaitForExit();
}
private void Escrita(string Texto)
{
    if (!string.IsNullOrEmpty(Texto))
    {
        BeginInvoke(new MethodInvoker(delegate
        {
            this.Texto.Text += Texto;
        }));
    }
}

对我来说,事件仅在文本更改时调用,而不仅仅是在VBoxManage转到新行时。有时文本为null,然后在使用为控件获取的文本之前放置一个检查结构。