BlueChameleon
BlueChameleon

Reputation: 934

Distinguishing between "file in use" and other exceptions in .NET

I am reading files from a directory. I need to handle a situation where my application tries to pickup a file which is still being written to by another process, which I have no control over.

I am assuming that by trying to open the file, which is still being written to by something else, I am going to get an exception. Now, I need to figure out whether there is something wrong with the file, in which case I move it to another directory or whether the second process is still writing to the file, in which case I would want to try again in second iteration of reading the directory.

Anyone know how I can distinguish between those two exceptions?

Upvotes: 1

Views: 63

Answers (2)

braintechd
braintechd

Reputation: 403

Update: See Hans Passant's answer for an actual good solution. Leaving the Handle tool as a reference because it helps in similar cases.

For a robust way to check whether the file is opened by a specific process you can use Handle. It's a command line tool but you might be able to use it for your situation.

Old answer:

One hacky solution could be to simple check the exception's message. If it includes

is being used by another process

Then your file is locked by another process (can't tell from the exception which one is it). Otherwise, it's some other I/O error.

Unfortunately, the documentation doesn't seem to say whether an IOException is thrown only on a handle violation (otherwise you'd be able to distinguish by whether the thrown exception is IOException or a derivative like FileNotFoundException).

Sample code:

catch (IOException ex)
{
    if (ex.Message.Contains("is being used by another process"))
    {
        // Retry logic goes here
    }
    else
    {
        // Other type of error (possibly derivative of IOException)
        throw;
    }
}

It's far from perfect, but the system message probably doesn't change too much.

Upvotes: 0

Hans Passant
Hans Passant

Reputation: 941495

You can use the Marshal.GetHRForException() method to recover the original Windows error that caused the IOException to be raised. An example:

static FileStream TryOpen(string path, int maxAttempts = 10, int interval = 1000) {
    for (int attempt = 0; ; attempt++) {
        try {
            return new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.None);
        }
        catch (IOException ex) {
            var err = System.Runtime.InteropServices.Marshal.GetHRForException(ex) & 0xffff;
            if (attempt < maxAttempts && err != 32) throw;
        }
        System.Threading.Thread.Sleep(interval);
    }
}

Upvotes: 4

Related Questions