ravi kumar
ravi kumar

Reputation: 1620

Copying a file when it is in use by another process

I am trying to write a program that watches over a folder and when any file in the folder gets changed/updated, it has to copy that file to another folder. In particular I want to use this program to copy dll files. Whenever I build a project using VS, the dll gets created, then I want my program to copy the newly generated dll to another folder.

The problem is that when I try to copy the file, I get an exception saying that The process cannot access the file because it is being used by another process. I know what this exception means and I've seen answers on SO on how to fix it (but in most cases the answers assume that the dev has control over the other process also). In my case I have no control over the other process that is using that file (probably VS ?).

Is it even possible to achieve this? If not then why am I able to manually copy that dll to another folder but cannot do it programmatically. Here's the code I use to copy the file.

private void CopyFile(object sender, FileSystemEventArgs e)
{
    string fileName = e.FullPath;
    try
    {
        System.Threading.Thread.Sleep(5000);
        File.Copy(fileName, System.IO.Path.Combine(DestinationFolderPath, fileName), true);
        this.Dispatcher.Invoke(() =>
        {
            Log.Text += "Copied " + e.Name + Environment.NewLine;
        });
    }
    catch (IOException exception)
    {
        this.Dispatcher.Invoke(() =>
        {
            Log.Text += "Error copying file " + e.Name + " " + exception.Message + Environment.NewLine;
        });
    }
}

Upvotes: 0

Views: 2665

Answers (3)

Jazimov
Jazimov

Reputation: 13292

You should activate shadow copying of your DLLs. Read more here: https://learn.microsoft.com/en-us/dotnet/framework/app-domains/shadow-copy-assemblies

Essentially, when you enable shadow copying (by setting the ShadowCopyFiles property to the string value "true"), all assemblies in the application path to be copied to a download cache before they are loaded. You can then copy the assemblies from the cache folder--those won't be locked.

Does that help?

Upvotes: 3

Sergey L
Sergey L

Reputation: 1492

If a file is opened exclusively by another application you hardly can anything about it, except using a disk shadow copy that is a little bit complex and it may return not a recent version of file.

Assuming you are not creating a backup application but some kind of a tool. If you may expect that other applications that create files are monitoring becomes free in reasonable time, all you need to do is to keep a list of failed coping operations and retry them in after a small delay.

If you are doing it for a certain application, for example, VS, it might be better if you use the Post Build event that you can find the project settings. For other application you may monitor exit code or something to find a moment when it finished processing files, so you can freely copy them.

Upvotes: 1

PhillipH
PhillipH

Reputation: 6222

You could be more subtle; rather than using the File.Copy helper method, you could try to open the file stream as for reading explicitly with a share parameter that allows multiple read streams open. If the file is not open for writing (and a DLL is probably not going to be open for writing, unless its being udpated, in which case copying it would be pointless) this allows you to copy a file open by another process.

You can read the docs on how to use FileStream.Open to copy a files contents to another file (the destination) using the flags FileAccess.Read and FileShare.ReadWrite

Upvotes: 1

Related Questions