【问题标题】:Has the actual behavior of FileStream.Lock(long, long) (or of the WINAPI method LockFile) changed since .NET 2.0 was originally released, and how?自 .NET 2.0 最初发布以来,FileStream.Lock(long, long)(或 WINAPI 方法 LockFile)的实际行为是否发生了变化,如何变化?
【发布时间】:2014-11-03 23:42:40
【问题描述】:

我最近注意到FileStream.Lock(long, long).NET 4.0.NET 4.5 中记录为保留独占该“进程”对文件指定范围的访问(但实际上是针对该 FileStream 实例或者更确切地说,对于它在内部引用的实际操作系统文件句柄)。另一方面,.NET 2.03.0 的文档表明其行为是阻止其他人更改文件(不写入该范围 - 即使是当前的 FileStream/句柄,我认为,虽然没有指出)同时 允许所有打开的 FileStreams/句柄的读取访问(假设 ShareMode 允许这样的重叠句柄)。 .NET 3.5 的文档将措辞更改为“防止其他人更改”(无法写入范围);这可能是对行为解释的更正或澄清,或者它可能是一个过渡文档,任何一种行为都可以真正满足(因为它没有指定其他人是否允许读取)而不指定其他访问或重叠锁将被允许或失败。

我以为我之前在 .NET 2.0 中尝试过这个 API,并确认了即使通过锁定 FileStream 也锁定了对锁定范围的写入,但那是几年前的事了,我的回忆可能有问题...... . 我当时可能只是简单地依赖文档,但我觉得我记得实际进行过实验,因为我想确保了解它实际上是如何工作的,并且因为文档在某些方面相当模糊。但是,Google 确实在另一个站点上找到了 this thread from 2007,这似乎表明 LockFile 并没有像人们期望的那样阻止读取访问,最终在底层操作系统中支持“独占访问”锁。

但是,最近在面向 .NET 4.0 和 .NET 2.0 的测试应用程序中进行的实验(在运行 Windows 7 的 64 位计算机上)发现两者都显示出相同的独占行为,如documentation for .NET 4.0。我无法确认 originally documented for .NET 2.0 的行为,我想我记得它过去的行为。

.NET 2.0 框架上的反编译器显示FileStream.Lock(long, long) 调用了 WINAPI 方法LockFile,然后进入 .NET 4.0 框架发现它也从那里调用了相同的 WINAPI 方法。在我找到的文档中,这种 WINAPI 方法被记录为保留“独占访问”。之前是否记录为保留共享只读访问权限?当 .NET 2.0 首次发布时(尤其是在 Windows XP 上),它以前是否具有共享只读访问权限?它的行为是否可能在 Windows Vista 或 Windows 7 上更改为独占访问,或者它是否总是按照 here 记录的那样进行独占访问?

另一方面,WINAPI 方法LockFileEx 采用dwFlags 参数,该参数可以指定指定范围的共享(可能是只读)或排他锁定。 FileStream.Lock(long, long) 方法是否在某个时候被 .NET 2.0 框架的补丁更改了,还是一直使用 LockFile

不幸的是,.NET 没有提供 FileStream.Lock() 的重载(或我发现的任何其他 API)来访问这种可选择的文件锁定行为,似乎也没有任何其他方法可以使用从FileStream.Lock(long, long) 本身使用的那个——当然除了通过 pInvoke 破解对 WINAPI 方法本身的调用......这对于某些项目是不允许的。

我希望有人能更明确地记住 FileStream.Lock(long, long) 方法和/或它显然调用的底层 WINAPI 方法 LockFile 的实际行为(至少在最新版本中) .NET 2.0 和 .NET 4.x) 或可能知道这些方法的历史,如果它们改变了它们的实际行为,记录的行为似乎在 .NET 2.0 和 .NET 4.0 之间发生变化,并且可以清除这些明显的不一致.

【问题讨论】:

    标签: .net winapi file-locking


    【解决方案1】:

    我知道你说过你不能破解 pinvoke,但如果可以,请查看 ZwLockFile,这是 LockFile 和 LockFileEx 最终调用的调用。

    至于 LockFile 在 Windows XP 时间范围内的行为,我从 2001 年挖出了我的 MSDN 副本:

    锁定文件

    LockFile 函数将一个区域锁定在一个打开的文件中。锁定区域可防止其他进程访问该区域。

    要指定其他选项,请使用 LockFileEx 函数。

    BOOL LockFile(
      HANDLE hFile,                   // handle to file
      DWORD dwFileOffsetLow,          // low-order word of offset
      DWORD dwFileOffsetHigh,         // high-order word of offset
      DWORD nNumberOfBytesToLockLow,  // low-order word of length
      DWORD nNumberOfBytesToLockHigh  // high-order word of length
    );
    

    参数

    h文件

    [in] 带有要锁定区域的文件的句柄。文件句柄 必须使用 GENERIC_READ 或 GENERIC_WRITE 访问权限创建 文件(或两者)。

    dwFileOffsetLow

    [in] 指定起始字节偏移量的低位字 锁定应该开始的文件。

    dwFileOffsetHigh

    [in] 指定起始字节偏移量的高位字 锁应该开始的文件。 Windows 95/98/Me:dwFileOffsetHigh 必须为 0,dwFileOffsetLow 值的符号扩展。任何 其他值将被拒绝。

    nNumberOfBytesToLockLow

    [in] 指定字节范围长度的低位字 被锁定。

    nNumberOfBytesToLockHigh

    [in] 指定字节范围长度的高位字 被锁定。

    返回值

    如果函数成功,则返回值非零。

    如果函数失败,返回值为零。要获取扩展错误信息,请调用 GetLastError。

    备注

    锁定文件的某个区域使锁定进程可以独占访问指定区域。文件锁不会被锁定进程创建的进程继承。

    锁定文件的区域会拒绝所有其他进程对指定区域的读写访问。锁定超出当前文件结尾位置的区域不是错误。

    锁不能与文件的现有锁定区域重叠。

    如果LockFile 无法锁定文件的某个区域,它会立即返回零。它不会阻塞。要发出将阻塞直到获得锁的文件锁请求,请使用不带 LOCKFILE_FAIL_IMMEDIATELY 的 LockFileEx。

    如果进程以文件的一部分被锁定而终止或关闭具有未完成锁定的文件,则锁定由操作系统解锁。但是,操作系统解锁这些锁所需的时间取决于可用的系统资源。因此,建议您的进程在终止时显式解锁所有已锁定的文件。如果不这样做,如果操作系统尚未解锁这些文件,访问这些文件可能会被拒绝。

    UnlockFile 函数解锁被 LockFile 锁定的文件区域。

    示例代码

    有关示例,请参阅读取、写入和锁定文件。

    要求

    Windows NT/2000/XP:包含在 Windows NT 3.1 及更高版本中。

    Windows 95/98/Me:包含在 Windows 95 及更高版本中。

    标头: 在 Winbase.h 中声明;包括 Windows.h。

    库:使用 Kernel32.lib。

    另见

    文件 I/O 概述、文件 I/O 函数、CreateFile、LockFileEx、UnlockFile

    平台 SDK 发布: 2001 年 8 月

    【讨论】:

    • 好的,所以 2001 年的文档声称 WINAPI LockFile 函数使用了“独占”行为。 (它仍然与 2007-2010 年左右一致吗?)感谢您的回答! (+1)这仍然留下了问题,即 .NET 2.0 最初/总是使用 WINAPI LockFile 和所描述的独占行为,还是(在某些时候)使用 WINAPI LockFileEx 和非独占(写保护)行为,后来改变了 (?. ..?) 使用 LockFile 和独占行为。
    • 早期的 dotnet 建立在现有的 WINAPI(基本上是互操作包装器)之上。我在 2.0 之前使用了 .NET 框架的早期测试版。当我们要求支持未涵盖的某某 WINAPI 时,他们告诉我们进行互操作,因为这基本上是大多数框架所做的:提供安全的互操作包装器。所以我冒昧地说,是的,它使用了 WINAPI LockFile。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多