Is there a way to check if a file is in use?

Viewed 658924

I'm writing a program in C# that needs to repeatedly access 1 image file. Most of the time it works, but if my computer's running fast, it will try to access the file before it's been saved back to the filesystem and throw an error:

"File in use by another process"

I would like to find a way around this, but all my Googling has only yielded creating checks by using exception handling. This is against my religion, so I was wondering if anyone has a better way of doing it?

20 Answers

Updated NOTE on this solution: Checking with FileAccess.ReadWrite will fail for Read-Only files so the solution has been modified to check with FileAccess.Read.

ORIGINAL: I've used this code for the past several years, and I haven't had any issues with it.

Understand your hesitation about using exceptions, but you can't avoid them all of the time:

protected virtual bool IsFileLocked(FileInfo file)
{
    try
    {
        using(FileStream stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None))
        {
            stream.Close();
        }
    }
    catch (IOException)
    {
        //the file is unavailable because it is:
        //still being written to
        //or being processed by another thread
        //or does not exist (has already been processed)
        return true;
    }

    //file is not locked
    return false;
}

You can suffer from a thread race condition on this which there are documented examples of this being used as a security vulnerability. If you check that the file is available, but then try and use it you could throw at that point, which a malicious user could use to force and exploit in your code.

Your best bet is a try catch / finally which tries to get the file handle.

try
{
   using (Stream stream = new FileStream("MyFilename.txt", FileMode.Open))
   {
        // File/Stream manipulating code here
   }
} catch {
  //check here why it failed and ask user to retry if the file is in use.
}

Perhaps you could use a FileSystemWatcher and watch for the Changed event.

I haven't used this myself, but it might be worth a shot. If the filesystemwatcher turns out to be a bit heavy for this case, I would go for the try/catch/sleep loop.

Aside from working 3-liners and just for reference: If you want the full blown information - there is a little project on Microsoft Dev Center:

https://code.msdn.microsoft.com/windowsapps/How-to-know-the-process-704839f4

Now found at: https://github.com/TacticalHorse/LockFinder/blob/master/LockFinder.cs

From the Introduction:

The C# sample code developed in .NET Framework 4.0 would help in finding out which is the process that is having a lock on a file. RmStartSession function which is included in rstrtmgr.dll has been used to create a restart manager session and according to the return result a new instance of Win32Exception object is created. After registering the resources to a Restart Manager session via RmRegisterRescources function, RmGetList function is invoked to check what are the applications are using a particular file by enumerating the RM_PROCESS_INFO array.

It works by connecting to the "Restart Manager Session".

The Restart Manager uses the list of resources registered with the session to determine which applications and services must be shut down and restarted. Resources can be identified by filenames, service short names, or RM_UNIQUE_PROCESS structures that describe running applications.

It might be a little overengineered for your particular needs... But if that is what you want, go ahead and grab the vs-project.

the only way I know of is to use the Win32 exclusive lock API which isn't too speedy, but examples exist.

Most people, for a simple solution to this, simply to try/catch/sleep loops.

I once needed to upload PDFs to an online backup archive. But the backup would fail if the user had the file open in another program (such as PDF reader). In my haste, I attempted a few of the top answers in this thread but could not get them to work. What did work for me was trying to move the PDF file to its own directory. I found that this would fail if the file was open in another program, and if the move were successful there would be no restore-operation required as there would be if it were moved to a separate directory. I want to post my basic solution in case it may be useful for others' specific use cases.

string str_path_and_name = str_path + '\\' + str_filename;
FileInfo fInfo = new FileInfo(str_path_and_name);
bool open_elsewhere = false;
try
{
    fInfo.MoveTo(str_path_and_name);
}
catch (Exception ex)
{
    open_elsewhere = true;
}

if (open_elsewhere)
{
    //handle case
}

Would something like this help?

var fileWasWrittenSuccessfully = false;
while (fileWasWrittenSuccessfully == false)
{
    try
    {
        lock (new Object())
        {
            using (StreamWriter streamWriter = new StreamWriter("filepath.txt"), true))
            {
                streamWriter.WriteLine("text");
            }
        }

        fileWasWrittenSuccessfully = true;
    }
    catch (Exception)
    {

    }
}

Try and move/copy the file to a temp dir. If you can, it has no lock and you can safely work in the temp dir without getting locks. Else just try to move it again in x seconds.

retry_possibility:
//somecode here

try
{
    using(FileStream stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None))
    {
        stream.Close();
    }
    //write or open your file here
}
catch (IOException)
{
    DialogResult dialogResult = MessageBox.Show("This file is opened by you or another user. Please close it and press retry.\n"+ expFilePath, "File Locked", MessageBoxButtons.RetryCancel);
    if (dialogResult == DialogResult.Retry)
    {
        goto retry_possibility;
    }
    else if (dialogResult == DialogResult.Cancel)
    {
        //do nothing
    }
}
Related