[英]Process stdout different in console vs when redirected
在Windows C#應用程序中,我們要運行cipher.exe來從未使用的磁盤空間(在本例中為D:驅動器)中刪除數據:
cipher.exe /w:D:\
從Windows命令行完成后,輸出為:
To remove as much data as possible, please close all other applications while
running CIPHER /W.
Writing 0x00
...................................................................................................
Writing 0xFF
...................................................................................................
Writing Random Numbers
...................................................................................................
這些帶有點的線在加密過程的持續時間內逐漸填充。 我們認為應該從C#應用程序中讀取這些點以跟蹤進度並將其顯示在進度條上。 但是,我們注意到,當捕獲或重定向標准輸出時,順序是不同的:
cipher.exe /w:D:\ > out.txt
結果文件包含以下內容:
To remove as much data as possible, please close all other applications while
running CIPHER /W.
Writing 0x00
Writing 0xFF
Writing Random Numbers
...................................................................................................
...................................................................................................
...................................................................................................
因此,當我們嘗試從C#應用程序中捕獲這些內容時,直到過程結束時才讀取點。 例如,當使用以下代碼時:
private void RunCipher()
{
using (Process cipherProcess = new Process())
{
try
{
// Cipher does three phases, one with 00s, one with FFs and one with random bits
// We count dots in the output for each phase to track the progress
// The amount of dots per phase is always 99 (independent of the volume size)
// See the end of this file to find the expected output
cipherProcess.StartInfo.FileName = "cipher.exe";
cipherProcess.StartInfo.Arguments = @"/w:D:\";
cipherProcess.StartInfo.RedirectStandardOutput = true;
cipherProcess.StartInfo.RedirectStandardError = true;
cipherProcess.StartInfo.RedirectStandardInput = true;
cipherProcess.StartInfo.UseShellExecute = false;
cipherProcess.StartInfo.CreateNoWindow = true;
cipherProcess.OutputDataReceived += CipherProcess_OutputDataReceived;
cipherProcess.ErrorDataReceived += CipherProcess_ErrorDataReceived;
cipherProcess.Exited += CipherProcess_Exited;
cipherProcess.Start();
cipherProcess.BeginOutputReadLine();
cipherProcess.BeginErrorReadLine();
cipherProcess.WaitForExit();
}
catch
{
Console.WriteLine("Exception occured");
}
}
Console.WriteLine("Fininshed");
}
private void CipherProcess_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
Console.WriteLine("OutputDataReceived: " + e.Data);
}
private void CipherProcess_Exited(object sender, EventArgs e)
{
Console.WriteLine("Exited");
}
private void CipherProcess_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
Console.WriteLine("ErrorDataReceived: " + e.Data);
}
輸出為:
OutputDataReceived: To remove as much data as possible, please close all other applications while
OutputDataReceived: running CIPHER /W.
OutputDataReceived: Writing 0x00
The thread 0x41ac has exited with code 0 (0x0).
The thread 0x408c has exited with code 0 (0x0).
OutputDataReceived: Writing 0xFF
The thread 0x39e4 has exited with code 0 (0x0).
The thread 0x3e30 has exited with code 0 (0x0).
OutputDataReceived: Writing Random Numbers
The thread 0x34ac has exited with code 0 (0x0).
The thread 0x3960 has exited with code 0 (0x0).
OutputDataReceived: ...................................................................................................
OutputDataReceived: ...................................................................................................
OutputDataReceived: ...................................................................................................
ErrorDataReceived:
OutputDataReceived:
Fininshed
我們還嘗試了不使用OutputDataReceived + BeginOutputReadLine而是使用process.StandardOutput.Read()的方法,但是它具有相同的問題:它首先讀取所有三個“ Writing(..)”輸出:
private void RunCipher2()
{
using (Process cipherProcess = new Process())
{
try
{
cipherProcess.StartInfo.FileName = "cipher.exe";
cipherProcess.StartInfo.Arguments = @"/w:D:\";
cipherProcess.StartInfo.RedirectStandardOutput = true;
cipherProcess.StartInfo.RedirectStandardError = true;
cipherProcess.StartInfo.RedirectStandardInput = true;
cipherProcess.StartInfo.UseShellExecute = false;
cipherProcess.StartInfo.CreateNoWindow = true;
cipherProcess.Start();
while (!cipherProcess.StandardOutput.EndOfStream)
{
char nextChar = (char)cipherProcess.StandardOutput.Read();
Console.Write(nextChar);
}
cipherProcess.WaitForExit();
}
catch
{
Console.WriteLine("Exception occured");
}
}
Console.WriteLine("Fininshed");
}
而且輸出仍然是我們無法期望的:
To remove as much data as possible, please close all other applications while
running CIPHER /W.
Writing 0x00
Writing 0xFF
Writing Random Numbers
...................................................................................................
...................................................................................................
...................................................................................................
Fininshed
我們已經找到了該線程,但是該解決方案需要將重定向的輸出進行首次工作: 在收到新行之前讀取Process StandardOutput
這里發生了什么事? 有沒有辦法使這項工作? 還是以其他方式跟蹤進度? 當然,我們可以檢測到“ Writing”消息,並以三分之二的速度報告進度……但是看來這應該是可能的:)
假設隨着進展的進行,“ ...”以遞增方式出現,那么您需要執行的操作是捕獲StandardOutput流並一次讀取一個字符,而不是使用DataRecieved事件。 這樣,您將看到每個句號被寫出來。 然后,您可以計算自己擁有的數量,並以此來推斷進度。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.