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
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().
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.
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);
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).
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.
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!");
}
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With