Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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."

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

like image 424
user1522008 Avatar asked Jul 12 '12 21:07

user1522008


People also ask

How to read the data from file in C?

Steps To Read A File:Open a file using the function fopen() and store the reference of the file in a FILE pointer. Read contents of the file using any of these functions fgetc(), fgets(), fscanf(), or fread(). File close the file using the function fclose().

What read function return in C?

The read() function reads data previously written to a file. If any portion of a regular file prior to the end-of-file has not been written, read() shall return bytes with value 0.

How read function work in C?

read: From the file indicated by the file descriptor fd, the read() function reads cnt bytes of input into the memory area indicated by buf. A successful read() updates the access time for the file. Syntax in C language size_t read (int fd, void* buf, size_t cnt);

Can multiple processes read the same file C?

During the actual reading and writing, yes. But multiple processes can open the same file at the same time, then write back. It's up to the actual process to ensure they don't do anything nasty. If your writing the processes, look into flock (file lock).


3 Answers

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.

like image 114
Reed Copsey Avatar answered Oct 26 '22 20:10

Reed Copsey


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

like image 23
IDK Avatar answered Oct 26 '22 22:10

IDK


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.

like image 2
Sam I am says Reinstate Monica Avatar answered Oct 26 '22 21:10

Sam I am says Reinstate Monica