15

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

请帮忙。提前致谢

4

3 回答 3

17

问题是您同时使用同步和异步输出:

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


StreamReader sr = xcopy.StandardOutput;

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

您需要设计您的算法以使用一个选项或另一个,但不能同时使用两者。

于 2012-07-12T21:12:53.130 回答
7

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

于 2012-07-13T15:08:46.013 回答
3

如果你想做同步的方式,

代替

xcopy.BeginOutputReadLine()

利用

string s = xcopy.StandardOutput.ReadToEnd()

请注意,如果您对输出和错误都这样做,并且其中一个太长,您可能会遇到死锁。

于 2012-07-12T21:13:42.400 回答