2010-02-25 4 views
12

Я использую VBOXMANAGE для «экспорта» гостевой машины. VBOXManage - это консольное приложение, которое может управлять поведением гостевой машины с хоста. Поскольку команда экспорта представляет собой длительный процесс, он возвращает обновление процесса следующим образом:Перенаправление выходных данных в режиме реального времени с использованием процесса

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

Я пишу C#, которое будет вызывать VBOXManage с помощью Process. Вот мой код:

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

Обратите внимание на название функции: BeginOutput * ReadLine * –

+0

Да, благодарю вас за это замечательное понимание. ;) – Ian

+0

Пара 'С'''''''''''''''''''''''''''''''''''' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ' – Basic

ответ

6

Вы можете прочитать непосредственно из StanadardOutput/Error для процесса, используя все стандартные методы Stream, просто установите для параметра 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.

Сон в петле высвобождает процессор для других задач и позволяет накапливать некоторые данные в буферах. Если период ожидания слишком длинный и переполнение буфера, какой-то вывод из процесса выполнения будет потерян. Если период ожидания слишком короткий, многие циклы процессора расходуются на чтение и пустой буфер.

+0

Привет, выше код несколько ненадежный ... Я получаю усеченные тексты. – Ian

+0

Да, в зависимости от времени записи в stdout и завершения процесса могут быть некоторые данные, оставшиеся в буфере после завершения цикла. Еще один прочитанный после того, как цикл заберет любые отсутствующие данные. В основном я хотел указать, что все методы потока доступны. В производственном коде я, скорее всего, буду спать или иным образом освобождать процессор в цикле и читать только «occacialally». – ScottS

+1

ReadToEnd() будет блокироваться во время работы процесса. – Herman

5

Это работало для меня

 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() мои методы.

+0

Будет работать только в том случае, если выходной поток завершен. Но в моем примере выходной поток находится в одной строке и только завершается, когда процесс выполняется. – Ian

0

Попробуйте перенаправить стандартный ввод и примените AutoFlush к стандарту. Следующий поток чтения с использованием 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; 
0

Извините, я ошибаюсь, я бразилец и использую Google Translate, чтобы написать этот текст.

Кстати, я также делаю программу, которая работает с VBoxManage Virtualbox. В моем случае я хотел, среди прочего, преобразовать виртуальный диск. Также он задерживает и процент с прогрессом также

Мне удалось сделать это, создав процесс воли для запуска программы и используя пользовательские классы «Dean North» другой question, который похож на этот. Важно использовать поток для запуска VBoxManage, иначе не получится обработать полученный текст или просмотреть прогресс.

O texto é muito grande pra eu adicionar quatro espaços antes de 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 переходит к новой строке. Иногда текст был нулевым, а затем помещал структуру проверки, как я делал, прежде чем использовать текст, полученный для элементов управления.

Смежные вопросы