我在C#中异步读取一个进程的输出时遇到问题。 我在这个网站上发现了一些其他类似的问题,但它们对我没有帮助。 这是我的工作:
它工作正常,但启动过程的输出写了一些我想要得到的百分比(%
),但我不能,因为我的代码逐行读取并且百分比没有出现。 / p>
示例:
%0,%1...%100
Finished.
我的输出:
%0
Finished.
以下是我的计划的当前代码:
StringBuilder sBuilder = new StringBuilder();
static void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
sBuilder.AppendLine(e.Data);
}
static void CommandExecutor()
{
Process process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = /*path of the program*/,
Arguments = /*arguments*/,
CreateNoWindow = true,
UseShellExecute = false,
WindowStyle = ProcessWindowStyle.Hidden,
RedirectStandardOutput = true
}
};
process.OutputDataReceived += new DataReceivedEventHandler(proc_OutputDataReceived);
process.Start();
process.BeginOutputReadLine();
process.WaitForExit();
}
答案 0 :(得分:7)
似乎异步读取流输出有点坏 - 在进程退出之前不会读取所有数据。即使您拨打Process.WaitForExit()
,即使您再拨打Process.Close()
(或Dispose()
),您仍然可以获得大量数据。有关完整的说明,请参阅http://alabaxblog.info/2013/06/redirectstandardoutput-beginoutputreadline-pattern-broken/,但解决方案基本上是使用同步方法。但是,为了避免死锁,你必须在另一个线程上调用其中一个:
using (var process = Process.Start(processInfo))
{
// Read stderr synchronously (on another thread)
string errorText = null;
var stderrThread = new Thread(() => { errorText = process.StandardError.ReadToEnd(); });
stderrThread.Start();
// Read stdout synchronously (on this thread)
while (true)
{
var line = process.StandardOutput.ReadLine();
if (line == null)
break;
// ... Do something with the line here ...
}
process.WaitForExit();
stderrThread.Join();
// ... Here you can do something with errorText ...
}
答案 1 :(得分:5)
Process.WaitForExit()将一直等到异步输出/错误流读取完成。不幸的是,对于Process.WaitForExit(超时)重载,情况并非如此。这就是Process类在内部执行的操作:
// ...
finally
{
if (processWaitHandle != null)
{
processWaitHandle.Close();
}
if (this.output != null && milliseconds == -1)
{
this.output.WaitUtilEOF();
}
if (this.error != null && milliseconds == -1)
{
this.error.WaitUtilEOF();
}
this.ReleaseProcessHandle(safeProcessHandle);
}
...所以只有在没有超时的情况下才会等待异步读取! 要修复它,只需在WaitForExit(timeout)返回true后调用无参数的WaitForExit():
// ...
if (process.WaitForExit( 10 * 1000 ) && process.WaitForExit() )
{
// Process'es OutputDataReceived / ErrorDataReceived callbacks will not be called again, EOF streams reached
}
else
{
throw new Exception("timeout");
}
有关详细信息,请阅读此处的评论:http://msdn.microsoft.com/en-us/library/ty0d8k56%28v=vs.110%29
答案 2 :(得分:1)
很少有事情妨碍它...... 控制台应用程序可能使用“\ b”退格键来覆盖百分比,它可能在每次写入后都不会刷新到stdout流,而BeginOutputReadLine可能会在给出数据之前等待行尾。
通过BeginRead了解如何继续阅读process.StandardOutput.BaseStream(此代码不是正确的异步,如果您在表单中的推送进度,则需要处理“\ b”):
while (true)
{
byte[] buffer = new byte[256];
var ar = myProcess.StandardOutput.BaseStream.BeginRead(buffer, 0, 256, null, null);
ar.AsyncWaitHandle.WaitOne();
var bytesRead = myProcess.StandardOutput.BaseStream.EndRead(ar);
if (bytesRead > 0)
{
Console.Write(Encoding.ASCII.GetString(buffer, 0, bytesRead));
}
else
{
myProcess.WaitForExit();
break;
}
}
答案 3 :(得分:0)
如何在process.StandardOutput上使用StreamReader,并使用Read()方法? http://msdn.microsoft.com/fr-fr/library/system.io.streamreader.read(v=vs.80).aspx