File.Open для доступа на чтение запрещен при выполнении файла в Windows - PullRequest
3 голосов
/ 10 августа 2011

У меня есть проблема с правами доступа к файлам при запуске файлов в Windows, которая, кажется, решается после следования совету на форуме [1], но я не могу понять, почему. Может быть, вы, ребята, можете помочь.

Я проверяю баннер файла, выполняя его (читая вывод консоли), а затем открывая тот же файл для чтения с помощью 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');

и время от времени я получаю "файл используется другим процессом". Из Википедии я знаю, что Windows установит блокировку на выполнение файлов, запрещающих доступ на запись [2], но я только читаю. Также процесс должен был остановиться уже при попытке открыть его.

Из сообщения на форуме может показаться, что добавление FileShare.ReadWrite поможет, и кажется, что оно делает:

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

Но я не понимаю, почему. Есть ли здесь условия гонки, которых я не вижу?

Кроме того, вызов File.Open, по-видимому, выполняется намного быстрее с FileShare.ReadWrite, а не по умолчанию (я полагаю, это FileShare.Read).

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

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

Ответы [ 4 ]

8 голосов
/ 10 августа 2011

Если вы не укажете параметр FileShare, по умолчанию для этой опции будет FileShare.None, фактически код в классе File просто выполняет это:

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

Что касается производительности, я могу только представить, что указание FileShare.ReadWrite означает, что Windows не требуется устанавливать блокировку файла.

Поскольку ошибка «файл используется другим процессом», которую вы получаете, устраняет ли эта проблема, если вы обернули использование переменной потока в блоке использования так, что поток удаляется, как только вы сделано?

using (var stream = File.Open('sample.exe', FileMode.Open, FileAccess.Read))
{
  //do something with the stream here
}
2 голосов
/ 10 августа 2011

Вы должны закрыть FileStream, а затем открыть новый FileStream.

FileShare необходим, когда приложения хотят предоставить общий доступ к файлу не только одному приложению, либо в приложении одновременно имеется несколько устройств чтения или записи.

Почему? Это становится грязным, когда каждый может читать и писать одновременно. В этом случае вам лучше явно установить его так, чтобы было ясно, что он становится беспорядочным. :)

1 голос
/ 10 августа 2011

Это связано с базовыми флагами Windows CreateFile API. Смотри http://msdn.microsoft.com/en-us/library/aa363858%28v=vs.85%29.aspx для обзора, http://blogs.msdn.com/b/larryosterman/archive/2004/05/13/131263.aspx для объяснения того, как NT (и последующие) загружают execs с FILE_SHARE_DELETE

И особенно это

http://blogs.msdn.com/b/oldnewthing/archive/2004/05/11/129759.aspx

Отличное объяснение того, как разрешение на совместное использование и желаемый доступ сочетаются друг с другом!

0 голосов
/ 07 ноября 2012

Кажется, что указание неправильного FileShare может запретить вам доступ к файлу. Если вы укажете FileShare.Read, но какое-то другое приложение в настоящее время имеет доступ для записи в этот файл, вы не сможете получить доступ к файлу, так как ваш FileShare.Read в настоящее время не удовлетворяется. FileShare.ReadWrite менее ограничен, потому что его легче удовлетворить. Источник: http://blogs.msdn.com/b/oldnewthing/archive/2004/05/11/129759.aspx

...