我正在使用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%“仅在实际流程完成后显示。
有没有办法实时捕获控制台输出?
谢谢!
答案 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,然后在使用为控件获取的文本之前放置一个检查结构。