Question System.IO.IOException - The process cannot access the file when copying and awaiting the thread?

Swatto

New member
Joined
Mar 9, 2018
Messages
4
Programming Experience
Beginner
Good Morning Everyone,

I currently have a file copy routine that uses streams and updates the progress bar on my UI, this works fine in a thread when I do not await the thread to finish but as soon as I do (which is the behavior I want) I get an error about the process not being able to access the file being copied. The copy still continues and finishes if I press OK but I do not know why it is occurring? The way I want it to work is that if I am copying multiple files it will start a thread to copy one file, wait for it to finish and then continue the foreach loop to the next file? I am doing all this so that the UI is not blocked.

frmMain.cs:
 private async void CopyFiles()
        {
            TextBox TextBox = (TextBox)(frmMain_TabControl.SelectedTab.Controls.Find("frmMain_TabPage_page_txtAddress", true)[0]);
            foreach (FileInfo file in m_FilesToCopy)
            {
                try
                {
                    frmMain_ProgressBar.Visible = true;
                    frmMain_lblCopyingFile.Visible = true;
                    string source = file.FullName;
                    string destination = TextBox.Text + "\\" + file.Name;
                    WriteText("Copying File:" + file.Name);
                    await Task.Factory.StartNew(() => { CopyFile(source,destination); });
                }
                catch (Exception e)
                {
                    MessageBox.Show(e.ToString());
                }
            }
            m_FilesToCopy.Clear();
        }

#region Copy File routine
        private void CopyFile(string source, string destination)
        {
            FileStream fsOut = new FileStream(destination, FileMode.Create); //error happens here
            FileStream fsIn = new FileStream(source, FileMode.Open);
            byte[] buffer = new byte[1048756]; //1 MB
            int readBytes;
            while ((readBytes = fsIn.Read(buffer,0,buffer.Length)) > 0)
            {
                fsOut.Write(buffer, 0, readBytes);
                frmMain_ProgressBar.Invoke(new Action(() =>
                    {
                    frmMain_ProgressBar.Value = (int)(fsIn.Position * 100 / fsIn.Length);
                    }));
            }
        }
        #endregion
 
Instead of performing the calculation in the invoked lambda, try performing the calculation first and assigning the result to a variable, then using that variable in the invoked lambda:
C#:
var progress = (int)(fsIn.Position * 100 / fsIn.Length);

frmMain_ProgressBar.Invoke(new Action(() =>
                                      {
                                          frmMain_ProgressBar.Value = progress;
                                      }));
 
Hi jmcilhinney,

I have just tried that but still get the error, also if I press continue to ignore the exception I get another exception in the foreach loop saying 'Collection was modified; enumeration operation may not execute' - I do not get these issues if I remove await.
 
I am probably using threading wrong or something? Can anyone help please. I want to the copy file routine to run for one file at a time until completion before continuing the foreach loop for the other files.
 
FileStream fsOut = new FileStream(destination, FileMode.Create); //error happens here
That's the destination file. Look into why you can't create/overwrite that path.
also if I press continue to ignore the exception I get another exception in the foreach loop saying 'Collection was modified; enumeration operation may not execute' -
That suggest the code foreach (FileInfo file in m_FilesToCopy), m_FilesToCopy is external to the CopyFile method. In similar cases I often use a Queue<string> instead, or ConcurrentQueue if it is accessed by multiple threads.
 
That's the destination file. Look into why you can't create/overwrite that path.

That suggest the code foreach (FileInfo file in m_FilesToCopy), m_FilesToCopy is external to the CopyFile method. In similar cases I often use a Queue<string> instead, or ConcurrentQueue if it is accessed by multiple threads.

Hi JohnH,

That error with regards to the file create/overwrite only happens when I use await. If I take the await off then everything is fine. The foreach is outside the thread, maybe I should look at putting that within the thread.
 
It might help if you provided the actual error message, rather than a vague approximation. Does it literally say "The process cannot access the file"? That said, I would definitely try JohnH's suggestion of using a ConcurrentQueue.
 
Back
Top Bottom