File.Open for read access denied on executing file in Windows

Vegar Westerlund picture Vegar Westerlund · Aug 10, 2011 · Viewed 16.2k times · Source

I have a problem with file permissions on executing files in Windows that seems to be solved after following a forum tip[1], but I cannot understand why. Maybe you guys can help.

I'm checking the banner of a file by executing it (reading the console output) and then opening the same file for reading afterwards using FileStream:

public void fileMD5(string filename) {
  if (!File.Exists(filename)) return NT.Fail("File does not exist: " + filename);

  BinaryReader stream = new BinaryReader(File.Open(filename,
      FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
  int bufferSize = 4096;
  byte[] buffer = new byte[bufferSize];
  int readBytes;
  while ((readBytes = stream.Read(buffer, 0, bufferSize)) > 0) {
    md5Hasher.TransformBlock(buffer, 0, readBytes, buffer, 0);
  }
  stream.Close();
}

fileMD5('sample.exe');

and every once in a while I would get "file is being used by another process". From Wikipedia I know that Windows will set a lock on executing files denying write access[2], but I'm only reading. Also the process should have stopped already when I try to open it.

From the forum post it would seem that adding a FileShare.ReadWrite would help and it seems that It does:

FileStream stream = File.Open('sample.exe', 
    FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

But I don't understand why. Is there a race condition here that I don't see?

Also the File.Open call seems to be much quicker with FileShare.ReadWrite instead of the default (which I guess is FileShare.Read).

[1] http://www.xtremevbtalk.com/archive/index.php/t-192118.html

[2] http://en.wikipedia.org/wiki/File_locking#In_Microsoft_Windows

Answer

lowds picture lowds · Aug 10, 2011

When you do not specify a FileShare parameter the default for this option is FileShare.None, in fact the code within the File class simply executes this:

public static FileStream Open(string path, FileMode mode, FileAccess access)
{
    return File.Open(path, mode, access, FileShare.None);
}

With regards to the performance I can only imagine that specifying FileShare.ReadWrite means that Windows does not need to aquire a lock on the file.

As far as the "file is being used by another process" error you are getting does this issue go away if you wrap the usage of the stream variable within a using block so that the Stream gets disposed of as soon as you are done?

using (var stream = File.Open('sample.exe', FileMode.Open, FileAccess.Read))
{
  //do something with the stream here
}