我在我的过程是试图读取日志文件,同时它也是目前仍然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 = new FileStream(name, FileMode.Open, FileAccess.Read, FileShare.Read);
任何人都可以揭示出这个行为的任何光线。 我在.NET 4%的Windows XP测试此。
var fileStream2 = new FileStream(..., FileShare.Read)
这种旅行了很多程序员。 每个人都假定该补充阅读共享。 它没有,原来的文件访问请求已经允许读取和重新确定它不会改变任何东西。 相反,它拒绝写入共享。 这不行,因为有人已经拿到写访问。 并使用它,你无法删除的权利。 所以,你的要求访问该文件将会失败。
您必须包括FileShare.Write。
实际发生的,就是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
:
允许读取该文件随后打开。
应该读作
该文件的后续访问仅用于读取限制,包括已经存在的锁的访问。
[更新]
我没有通过代码分析,但似乎这两个环节可以在构造函数的内部运作过一些启发:
内部构造函数的FileStream
内部的FileStream Init方法
我想我已经找到了文档中的答案的CreateFile 。
在讨论dwShareMode
参数,它说:
FILE_SHARE_READ 00000001启用上的文件或设备请求读访问后续打开操作。 否则,如果他们要求读访问其他进程无法打开文件或设备。 如果没有指定这个标志,但该文件或设备已经打开读访问,则操作失败。
FILE_SHARE_WRITE 0x00000002启用上的文件或设备的请求写访问后续打开操作。 否则,如果他们要求写访问其他进程无法打开文件或设备。 如果没有指定这个标志,但该文件或设备已被打开进行写访问或有写入权限的文件映射,函数调用失败。
这从根本上改变了我的文件共享是如何工作的认识。
你传递第四个参数
分享
它确定如何将文件将由进程共享的常量。
确定什么模式他人可以打开该文件。 所以很明显 - 当你试图打开该文件与文件共享模式“读”,并已经在写模式打开同一个文件 - 操作失败。