我正在使用xcopy编写备份程序,因为有很多大文件需要一段时间,所以我想显示进度。当我尝试使用StreamReader获取标准输出时,我在调试时会出现此错误消息。 “不能在进程流上混合同步和异步操作。”
public void backup_worker_DoWork(object sender, DoWorkEventArgs e)
{
int loop = 1;
backup_worker.WorkerReportsProgress = true;
Process xcopy = new Process();
ProcessStartInfo startinfo = new ProcessStartInfo();
startinfo.CreateNoWindow = true;
startinfo.UseShellExecute = false;
startinfo.RedirectStandardError = true;
startinfo.RedirectStandardOutput = true;
startinfo.FileName = Environment.CurrentDirectory + "\\xcopy.exe";
startinfo.Arguments = '"' + source + '"' + " " + '"' + target + '"' + " " + "/s /e /y";
xcopy.StartInfo.RedirectStandardOutput = true;
xcopy.StartInfo = startinfo;
xcopy.Start();
xcopy.BeginErrorReadLine();
xcopy.BeginOutputReadLine();
StreamReader sr = xcopy.StandardOutput;
while (loop > 0)
{
progress = sr.ReadLine();
output_list.Items.Add(progress);
}
xcopy.OutputDataReceived += new DataReceivedEventHandler(backup_worker_OutputDataRecieved);
xcopy.ErrorDataReceived += new DataReceivedEventHandler(backup_worker_ErrorDataReceived);
xcopy.WaitForExit();
backup_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backup_worker_RunWorkerCompleted);
}
void backup_worker_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
}
void backup_worker_OutputDataRecieved(object sender, DataReceivedEventArgs e)
{
}
void backup_worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Completed");
}
请帮忙。 提前致谢
答案 0 :(得分:10)
问题是您正在使用同步和异步输出:
// Using async version here...
xcopy.BeginOutputReadLine();
StreamReader sr = xcopy.StandardOutput;
while (loop > 0)
{
// Trying to use synchronous reading here
progress = sr.ReadLine();
您需要将算法设计为使用一个选项或另一个选项,但不能同时使用这两个选项。
答案 1 :(得分:5)
以下来自MSDN的说明应该非常清楚,问题是什么
您不能在重定向的流上混合异步和同步读取操作。在异步或同步模式下打开Process的重定向流后,该流上的所有进一步读取操作必须处于相同模式。例如,不要跟随BeginErrorReadLine在StandardError流上调用ReadLine,反之亦然。但是,您可以在不同模式下读取两个不同的流。例如,您可以调用BeginErrorReadLine,然后为StandardOutput流调用ReadLine。
您的代码应该更多如下所示
public void backup_worker_DoWork(object sender, DoWorkEventArgs e) {
int loop = 1;
// This should ideally not be in the DoWork, but where you setup or create the worker
backup_worker.WorkerReportsProgress = true;
backup_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backup_worker_RunWorkerCompleted);
backup_worker.WorkerSupportsCancellation = true;
// setup your scopy process
ProcessStartInfo startinfo = new ProcessStartInfo();
startinfo.CreateNoWindow = true;
startinfo.UseShellExecute = false;
startinfo.RedirectStandardError = true;
startinfo.RedirectStandardOutput = true;
startinfo.FileName = Environment.CurrentDirectory + "\\xcopy.exe";
startinfo.Arguments = "/s /e /y " + '"' + source + '"' + " " + '"' + target + '"' + " ";
Process xcopy = new Process();
xcopy.StartInfo = startinfo;
xcopy.ErrorDataReceived += new DataReceivedEventHandler(backup_worker_ErrorDataReceived);
// start the xcopy and read the output
xcopy.Start();
xcopy.BeginErrorReadLine();
string copiedFileName;
while ((copiedFileName = xcopy.StandardOutput.ReadLine()) != null) {
output_list.Items.Add(copiedFileName);
}
// we should be done when here, but doesen't hurt to wait
xcopy.WaitForExit();
}
void backup_worker_ErrorDataReceived(object sender, DataReceivedEventArgs e) {
MessageBox.Show("We have a problem. Figure what needs to be done here!");
}
void backup_worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true) {
MessageBox.Show("Canceled!");
} else if (e.Error != null) {
MessageBox.Show("Error: " + e.Error.Message);
} else {
MessageBox.Show("Completed!");
}
}
答案 2 :(得分:3)
如果你想做同步方式,
而不是
xcopy.BeginOutputReadLine()
使用
string s = xcopy.StandardOutput.ReadToEnd()
要注意,如果你为输出和错误都这样做,并且其中一个太长,你就可以遇到死锁。