views:

1082

answers:

6

I have an application where i sometimes need to read from file being written to and as a result being locked. As I have understood from other questions i should catch the IOException and retry until i can read.

But my question is how do i know for certain that the file is locked and that it is not another IOExcetpion that occurs.

A: 

To read data you can do:

using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete)) { .... }

and to save into file:

using (FileStream fs = new FileStream(fileName, FileMode.Append, FileAccess.Write, FileShare.Read | FileShare.Delete)) { ... }

Flags at the end of constructors describes what other process can do with the file. It is fine, of course, if you control both write and read...

bezieur
A: 

You can compare against the type IOException to check and see if it is not something else

Such as

if (ex is FileNotFoundException)

You might want to look up the help on System.IO. A lot of the exceptions in that class inherit from IOException. Outside of checking to see if it is another type of exception you may have to look in the message of the description or you might look into making a Win32 API call into shell32.dll. There may be a function in there to check if a file is locked.

Also, if you absolutely need to wait you can use loop, but if you want to do other actions while waiting use an asynchronous thread.

Billkamm
A: 

You may open it (as described by bezieur) then try to lock sections (or whole file) : http://www.java2s.com/Code/VB/File-Directory/Lockandunlockafile.htm

François
A: 

Do you mean you are both reading and writing to the file? Or that an external application is writing to it.

If you are doing the reading and writing then I assume you're doing it on different threads in which case take a look at the ReaderWriteLock class which will do this the management for you, and allow you to provide timeouts.

http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlock.aspx

Otherwise all you need to do is open the file in a read only mode. Then you shouldn't have any problems:

fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read));
Ian
+4  A: 

When you open a file for reading in .NET it will at some point try to create a file handle using the CreateFile API function which sets the error code which can be used to see why it failed:

const int ERROR_SHARING_VIOLATION = 32;
try
{
    using (var stream = new FileStream("test.dat", FileMode.Open, FileAccess.Read, FileShare.Read))
    {
    }
}
catch (IOException ex)
{
    if (Marshal.GetLastWin32Error() == ERROR_SHARING_VIOLATION)
    {
        Console.WriteLine("The process cannot access the file because it is being used by another process.");
    }
}
Darin Dimitrov
Unfortunately, you can't be certain that the Win32 error was really caused by the CreateFile API call. This might change in another version of the framework. To be certain, call the Win32 API yourself.
Pontus Gagge
+2  A: 

There's a useful discussion on google groups which you really should read. One of the options is close to darin's; however, to guarantee you get the right win32 error, you really should call the win32 OpenFile() API yourself (otherwise, you really don't know which error you are retrieving).

Another is to parse the error message: that will fail if your application is run on another language version.

A third option is to hack inside the exception class with reflection to fish out the actual HRESULT.

None of the alternatives are really that attractive: the IOException hierarchy would benefit from a few more subclasses IMHO.

Pontus Gagge