I am trying to read the output of a process in c# but I get this message “Cannot mix synchronous and asynchronous operation on process stream.”

佐手、 提交于 2019-12-06 21:30:13

问题


I am writing a backup program using xcopy and because there are a lot of large files it takes a while so I want to show the progress. When I try to use StreamReader to get the standard output, it has this error message when I debug. "Cannot mix synchronous and asynchronous operation on process stream."

  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");
    }

Please help. Thanks in advance


回答1:


The problem is that you're using both synchronous and asynchronous output:

// Using async version here...
xcopy.BeginOutputReadLine();


StreamReader sr = xcopy.StandardOutput;

while (loop > 0)
{
    // Trying to use synchronous reading here
    progress = sr.ReadLine();

You need to design your algorithm to use one option or the other, but not both.




回答2:


The below note from MSDN should make it very clear, what the problem is

You cannot mix asynchronous and synchronous read operations on a redirected stream. Once the redirected stream of a Process is opened in either asynchronous or synchronous mode, all further read operations on that stream must be in the same mode. For example, do not follow BeginErrorReadLine with a call to ReadLine on the StandardError stream, or vice versa. However, you can read two different streams in different modes. For example, you can call BeginErrorReadLine and then call ReadLine for the StandardOutput stream.

Your code should be more on the lines as below



    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!");
        }
    }




回答3:


If you want to do the synchronous way,

instead of

xcopy.BeginOutputReadLine()

use

string s = xcopy.StandardOutput.ReadToEnd()

be warned, that if you do that for both the output and the error, and one of them is too long, you can hit a deadlock.



来源:https://stackoverflow.com/questions/11460606/i-am-trying-to-read-the-output-of-a-process-in-c-sharp-but-i-get-this-message-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!