Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/317.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 文件共享未按预期工作_C#_.net_File Sharing_File Security - Fatal编程技术网

C# 文件共享未按预期工作

C# 文件共享未按预期工作,c#,.net,file-sharing,file-security,C#,.net,File Sharing,File Security,我有一个文件共享问题,我的进程试图读取一个日志文件,而该文件目前仍由NLog打开。在诊断这个问题时,我发现了一些令人惊讶的事情。以下操作失败: using (var fileStream1 = new FileStream("test.file", FileMode.Append, FileAccess.Write, FileShare.Read)) using (var fileStream2 = new FileStream("test.file", FileMode.Open, FileA

我有一个文件共享问题,我的进程试图读取一个日志文件,而该文件目前仍由NLog打开。在诊断这个问题时,我发现了一些令人惊讶的事情。以下操作失败:

using (var fileStream1 = new FileStream("test.file", FileMode.Append, FileAccess.Write, FileShare.Read))
using (var fileStream2 = new FileStream("test.file", FileMode.Open, FileAccess.Read, FileShare.Read))
{
}
第二个
FileStream
构造函数调用失败,原因是:

System.IO.IOException was unhandled
  Message=The process cannot access the file 'c:\...\test.file' because it is being used by another process.
  Source=mscorlib
  StackTrace:
       at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
       at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath)
       at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
尽管第一个
FileStream
表明它愿意共享读取。我发现更令人惊讶的是,这是有效的:

using (var fileStream1 = new FileStream("test.file", FileMode.Append, FileAccess.Write, FileShare.Read))
using (var fileStream2 = new FileStream("test.file", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
}
嗯,是的,在打开第二个流时请求更多访问实际上绕过了这个问题。我完全搞不懂为什么会这样,只能假设我误解了什么。我已经通读了API文档,但它们只是支持我当前的心智模型,说明它应该如何工作,而不是如何工作

以下是来自以下网站的一些支持性引用:

此枚举的典型用途是定义两个进程 可以同时读取同一文件。例如,如果文件是 如果指定了“已打开并读取”,则其他用户可以打开该文件进行读取 阅读而非写作

这里还有一块宝石:

以下FileStream构造函数打开现有文件并授予 对其他用户的只读访问(只读)

FileStream s2=newfilestream(名称,FileMode.Open,FileAccess.Read,FileShare.Read)


有人能解释一下这种行为吗。我正在.NET 4%Windows XP上测试这个问题。

您通过的第四个参数

分享
确定进程如何共享文件的常量


确定其他人可以以何种模式打开文件。因此,很明显,当您试图以文件共享模式“读取”打开文件,并且已经以写入模式打开同一文件时,操作失败。

实际发生的情况是,
fileStream2
无法更改对已通过
fileStream1
打开以进行写入(或追加)的文件的后续访问

fileStream2
将成功打开该文件,留下一个
FileShare.Read
作为“遗留”文件供后续访问,只有在没有已对其具有
Write
文件访问权限的进程时。更重要的是,在我们的示例中,我们讨论的是相同的过程。从另一个文件流修改文件流的属性没有多大意义,不是吗

也许下面的比较更能说明这一点:

// works
using (var fileStream1 = new FileStream("test.file", FileMode.OpenOrCreate, FileAccess.Read, FileShare.ReadWrite))
using (var fileStream2 = new FileStream("test.file", FileMode.Append, FileAccess.Write, FileShare.Read))
using (var fileStream3 = new FileStream("test.file", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
}

// fails
using (var fileStream1 = new FileStream("test.file", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
using (var fileStream2 = new FileStream("test.file", FileMode.Append, FileAccess.Write, FileShare.Read))
using (var fileStream3 = new FileStream("test.file", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
}
在我看来,
FileShare.Read的描述短语是:

允许随后打开文件进行读取

应理解为

对文件的后续访问仅限于读取, 包括对现有锁的访问

[更新]

我还没有分析过代码,但这两个链接似乎可以让我们了解构造函数的内部功能:


我想我已经在的文档中找到了答案

在讨论
dwShareMode
参数时,它说:

文件共享\u读取0x00000001 启用文件或设备上的后续打开操作以请求读取访问。 否则,如果其他进程请求读取访问,则无法打开文件或设备。 如果未指定此标志,但文件或设备已打开以进行读取访问,则函数将失败

文件共享写入0x00000002 启用文件或设备上的后续打开操作以请求写入访问权限。 否则,如果其他进程请求写访问权限,则无法打开文件或设备。 如果未指定此标志,但文件或设备已打开以进行写访问,或者具有具有写访问权限的文件映射,则该功能将失败。

这从根本上改变了我对文件共享工作原理的理解

 var fileStream2 = new FileStream(..., FileShare.Read)
这让许多程序员大吃一惊。每个人都认为这增加了读共享。它没有,原始文件访问请求已经允许读取并再次指定它不会改变任何东西。相反,它拒绝写共享。这是行不通的,因为有人已经有写权限了。并且正在使用它,您不能删除该权限。因此,访问该文件的请求将失败


您必须包括FileShare.Write。

它不是第三个,而是第四个。和
FileShare.Read
允许随后打开文件进行读取。FileShare.Read-“允许随后打开文件进行读取”-但不允许写入。您已经打开了文件以写入该共享模式禁止的内容。这个函数应该做什么?顺便问一下,关于“后续”你从哪里得到的?我的答案中引用的是MSDN,这里没有关于后续的内容。在对FileStream本身的描述中,没有关于后续过程的内容。甚至更多的标志源于WinAPi,并且始终与所有进程一起使用。(如果您在读取文件时禁止修改文件,那么允许将其修改给以前打开过它的人是没有意义的)。所以这在enum中不是很好的描述。尽管读了几遍你的答案,但仍然没有点击。我发现很难相信API文档是完全错误的。例如,“例如,如果打开了一个文件并指定了
Read
,其他用户可以打开该文件进行阅读,但不能进行写入。”这正是我在示例中试图做的,但它不起作用。@KentBoogaart:我不知道它是否相关(我也不明白),但关键短语可能是“其他用户”。对“其他用户”更好的测试应该是多线程测试。@Chris:我真正的场景是多线程测试(试图在后台诊断线程上收集日志)。此外,文档在描述共享行为时明确表示“通过此流程或其他流程”。这很公平。我想看了一下这个(尽管我需要一份重构的副本来看看.NET代码中这是多么真实)是