File.Open 在 Windows 中执行文件时拒绝读取访问

问题描述 投票:0回答:4

我在 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);

但我不明白为什么。这里有我没有看到的竞争条件吗?

此外,使用 FileShare.ReadWrite 而不是默认值(我猜是 FileShare.Read),File.Open 调用似乎要快得多。

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

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

c# windows file-locking
4个回答
12
投票

当您未指定 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 块中,以便在完成后立即处理流,那么这个问题是否会消失?

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

2
投票

您应该关闭 FileStream,然后打开一个新的 FileStream。

当应用程序想要共享文件而不仅仅是一个应用程序或一个应用程序同时有多个读取器或写入器时,需要 FileShare。

为什么?当每个人都可以同时读写时,事情就会变得混乱。在这种情况下,您应该更好地显式设置它,以便清楚地显示它会变得混乱。 :)


1
投票

它与底层 Windows API CreateFile 标志有关。 请参阅 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(及后续)如何使用 FILE_SHARE_DELETE 加载执行程序的解释

特别是这个:FILE_SHARE_* 位如何与所需的访问位交互? 有关共享权限和所需访问权限如何组合在一起的精彩解释!


1
投票

似乎指定错误的 FileShare 会禁止您访问文件。如果您指定

FileShare.Read
但某些其他应用程序当前具有对该文件的写入访问权限,则您无法访问该文件,因为您的 FileShare.Read 当前无法满足。 FileShare.ReadWrite 的限制较少,因为它更容易满足。来源:FILE_SHARE_* 位如何与所需的访问位交互?

© www.soinside.com 2019 - 2024. All rights reserved.