我试图在c#中读取进程的输出但是我收到此消息“无法在进程流上混合同步和异步操作”。

时间:2012-07-12 21:01:35

标签: c# process backgroundworker

我正在使用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");
    }

请帮忙。 提前致谢

3 个答案:

答案 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()

要注意,如果你为输出和错误都这样做,并且其中一个太长,你就可以遇到死锁。