【发布时间】:2018-06-28 15:18:56
【问题描述】:
我们要从 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
我们已经找到了这个线程,但是该解决方案需要重定向的输出才能首先工作:Read Process StandardOutput before New Line Received
这里发生了什么?有没有办法使这项工作?或者以其他方式跟踪进度?当然,我们可以检测到“Writing”消息并以三分之二报告进度……但这似乎应该是可能的:)
【问题讨论】:
标签: c# windows asynchronous process stdout