C# 使用进程的实时控制台输出重定向

C# 使用进程的实时控制台输出重定向,c#,process,console-redirect,C#,Process,Console Redirect,我正在使用VBOXMANAGE“导出”来宾计算机。VBOXManage是一个控制台应用程序,可以从主机控制来宾计算机的行为。由于export命令是一个很长的过程,因此它会返回如下过程更新: 0%…10%…20%…30%…100% 我正在编写一个C#应用程序,它将使用进程调用VBOXManage。这是我的密码: Process VBOXProc = new Process(); VBOXProc.StartInfo.FileName = VBOXMANAGE; VBOXProc.StartInf

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

0%…10%…20%…30%…100%

我正在编写一个C#应用程序,它将使用进程调用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();
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;
        }));
    }
}
这很好,只是输出是每行读取的。这意味着流程将更新“ “0%…10%…20%…30%…100%”仅在实际流程完成后显示

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


谢谢

您可以使用所有标准流方法直接从StandardOutput/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.StatardOutput.BaseStream.BeginRead(…)进行异步读取

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

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

这对我来说很有效:

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

错误。AppendLine()
SetMessage()
是我使用的方法。

尝试重定向标准输入,并对标准输入应用自动刷新。接下来使用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;

对不起,有任何错误,我是巴西和使用谷歌翻译写这篇文章

巧合的是,我也在做一个与Virtualbox的VBoxManage一起工作的程序。在我的例子中,除其他外,我希望转换一个虚拟磁盘。它也会延迟,并且进度百分比也会增加

我通过创建一个运行程序的意志过程,并使用一个用户类“Dean North”来实现这一点,另一个类似于此。使用线程运行VBoxManage非常重要,否则无法处理获取的文本或查看进度

O《欧盟宪法》第四章,内容涉及《宪法》和《宪法》的内容

这些类将替换
进程
系统类。无需对代码进行任何更改,只需添加一个arquivo.cs,其中包含用户传递的文本
Dean North
,而不是
Process p=new Process()
使用
FixedProcess p=new FixedProcess()

之后就是我的代码:

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();
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转到新行时调用。有时文本为空,然后像我使用为控件获取的文本之前那样放置一个检查结构。

注意函数名:BeginOutput ReadLine是的,感谢nobugz的精彩见解。)几个带有语句的
,将使代码更容易被人看到(和剪贴板)<代码>使用VBOXProc。。。与。StartInfo。。。以…结束。。。以
结尾。您好,上面的代码有点不可靠。。。我得到的是被截断的文本。是的,根据写入标准输出和进程终止的时间,在循环终止后,缓冲区中可能会留下一些数据。循环后的另一次读取将拾取任何丢失的数据。我主要想指出的是,所有的流方法都是可用的。在生产代码中,我可能会休眠或以其他方式释放循环中的处理器,并仅“偶尔”读取。ReadToEnd()将在进程运行时阻塞。仅当输出流终止时才会工作。但在我的示例中,输出流位于一行上,并且仅在流程完成时终止。