2010-02-25 33 views
12

Tôi đang sử dụng VBOXMANAGE để "xuất" máy khách. VBOXManage là một ứng dụng Console có thể điều khiển hành vi của máy khách từ máy chủ. Kể từ khi lệnh xuất khẩu là một quá trình lâu dài, nó sẽ trả về thông tin cập nhật quá trình như vậy:Chuyển hướng đầu ra của Bảng điều khiển thời gian thực bằng quy trình

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

Tôi viết một Ứng dụng C# sẽ gọi VBOXManage bằng Process. Đây là mã của tôi:

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

Điều này là tốt, ngoại trừ đầu ra được đọc trên mỗi LINE. Điều này có nghĩa là quá trình cập nhật " 0% ... 10% ... 20% ... 30% ... 100%" sẽ chỉ hiển thị SAU KHI quá trình thực tế được thực hiện.

Có cách nào để nắm bắt đầu ra của bàn điều khiển trong thời gian thực không?

Cảm ơn!

+0

Lưu ý tên hàm: BeginOutput * ReadLine * –

+0

Có, cảm ơn bạn nobugz vì cái nhìn sâu sắc tuyệt vời đó. ;) – Ian

+0

Một vài câu lệnh 'With' sẽ làm cho mã đó dễ dàng hơn nhiều trên mắt (và clipboard) ...' Với VBOXProc ... Với .StartInfo ... Kết thúc bằng ... Kết thúc bằng'. – Basic

Trả lời

6

Bạn có thể đọc trực tiếp từ StanadardOutput/Error cho quá trình sử dụng tất cả các phương thức Stream chuẩn, chỉ cần đảm bảo đặt StartInfo.Redirectxxx thành 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()); 

Ở trên sẽ lặp lại đầu ra của quy trình con cho ứng dụng của bạn Chuẩn Out.

Bạn có thể đọc Khối có kích thước cụ thể bằng cách sử dụng lệnh p.StandardOutput.Read (char [], int, int) hoặc không đồng bộ bằng p.StadardOutput.BaseStream.BeginRead (...).

Tất cả các phương thức tương tự đều có sẵn cho StandardError.

Ngủ trong vòng lặp giải phóng bộ xử lý cho các tác vụ khác và cho phép một số dữ liệu tích lũy trong bộ đệm. Nếu thời gian ngủ quá dài và bộ đệm tràn một số đầu ra từ quá trình thực hiện sẽ bị mất. Nếu khoảng thời gian ngủ quá ngắn thì rất nhiều chu kỳ CPU được dùng để đọc và bộ đệm trống.

+0

Xin chào, mã ở trên có phần không đáng tin cậy ... Tôi nhận được văn bản cắt ngắn. – Ian

+0

Có, tùy thuộc vào thời gian ghi để stdout và quá trình chấm dứt có thể có một số dữ liệu còn lại trong bộ đệm sau khi vòng lặp kết thúc. Đọc khác sau khi vòng lặp sẽ nhận bất kỳ dữ liệu bị thiếu. Tôi chủ yếu muốn chỉ ra rằng tất cả các phương pháp dòng có sẵn. Trong mã sản xuất, tôi có thể sẽ ngủ hoặc giải phóng bộ xử lý trong vòng lặp và chỉ đọc "thỉnh thoảng". – ScottS

+1

ReadToEnd() sẽ chặn trong khi tiến trình đang chạy. – Herman

5

này làm việc cho tôi

 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() và SetMessage() là phương pháp của tôi.

+0

Sẽ chỉ hoạt động nếu luồng đầu ra bị chấm dứt. Nhưng với ví dụ của tôi, luồng đầu ra nằm trên một dòng, và chỉ kết thúc khi quá trình được thực hiện. – Ian

0

Cố gắng chuyển hướng đầu vào tiêu chuẩn quá và áp dụng Tự động điền vào StandardInput. Luồng đọc tiếp theo bằng 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

Xin lỗi, tôi là người Brazil và sử dụng Google Dịch để viết văn bản này.

Thật trùng hợp, tôi cũng đang làm một chương trình hoạt động với VBoxManage của Virtualbox. Trong trường hợp của tôi, tôi muốn, trong số những thứ khác, chuyển đổi một đĩa ảo. Ngoài ra sự chậm trễ và tỷ lệ phần trăm với tiến độ cũng là

Tôi đã thực hiện điều này bằng cách tạo quy trình sẽ chạy chương trình và sử dụng một lớp người dùng 'Dean North` khác question tương tự như vậy. Điều quan trọng là sử dụng một chuỗi để chạy VBoxManage, nếu không sẽ không có cách nào để làm việc văn bản thu được hoặc xem tiến trình.

O texto é muito grande pra eu adicionar quatro espaços antes de cada linha e repassar.

Các lớp thay thế lớp hệ thống Process. Cần không thực hiện bất kỳ thay đổi mã của bạn, chỉ cần thêm một arquivo.cs với văn bản thông qua bởi người sử dụng Dean North thay vì Process p = new Process() sử dụng FixedProcess p = new FixedProcess()

Sau đó là mã của tôi:

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

Đối với tôi sự kiện chỉ được gọi khi văn bản được thay đổi, không chỉ khi VBoxManage chuyển sang một dòng mới. Đôi khi văn bản là null, sau đó đặt một cấu trúc kiểm tra như tôi đã làm trước khi sử dụng văn bản thu được cho điều khiển.

Các vấn đề liên quan