使用 FileShare.Delete 打开的已删除文件的行为是否在 Windows 上发生了变化?

Did the behaviour of deleted files open with FileShare.Delete change on Windows?

我们多年来一直在使用以下代码。

    /// <summary>
    /// Opens a file and returns an exclusive handle. The file is deleted as soon as the handle is released.
    /// </summary>
    /// <param name="path">The name of the file to create</param>
    /// <returns>A FileStream backed by an exclusive handle</returns>
    /// <remarks>If another process attempts to open this file, they will recieve an UnauthorizedAccessException</remarks>
    public static System.IO.FileStream OpenAsLock(string path)
    {
        var stream = TranslateIOExceptions(() => System.IO.File.Open(path, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write, System.IO.FileShare.Delete));
        System.IO.File.Delete(path);
        return stream;
    }

根据记忆,此代码用于 将文件保留在原位,直到 FileStream 关​​闭。该技术被用作协作并发锁的一部分。

我发现了一些其他问题,这些问题让我觉得过去的行为正如评论所描述的那样:文件保持原位,直到返回的文件流关闭。

Will we ever be able to delete an open file in Windows?

Can using FileShare.Delete cause a UnauthorizedAccessException?

但是,作为调查的一部分,我发现 Windows 并非如此。相反,一旦调用 File.Delete,文件就会被删除。我还尝试重现 Hans 建议的上述错误 link 但没有成功。

class Program
{
    static void Main(string[] args)
    {
        File.Open("test", FileMode.OpenOrCreate, FileAccess.Write, FileShare.Delete);
        File.Delete("test");
        File.WriteAllText("test", "hello world");
        Console.Write(File.ReadAllText("test"));
        Console.ReadLine();
    }
}

不幸的是,我们的单元测试可能捕捉到这种行为变化,但在我们的环境中未正确配置为 运行 每晚,所以我无法确定它是否曾经 运行绿色.

这是真正的行为改变吗?我们知道它是什么时候发生的吗?是故意的(记录在案)吗?

非常感谢 Eryk 的提示。

事实证明,我们确实有几个单元测试可以捕捉到这种行为变化,包括明确测试这种行为的测试。我怀疑这些是在首先调查这种奇怪行为时添加的。

单元测试尚未发出警报,因为我们的测试机器 运行 比我的开发机器更旧 Windows 10。

  • Build 17134.1304 肯定有旧行为。
  • Build 18363.657 肯定有新行为。

我查看了 list of build releases and, unfortunately, there were over two dozen releases between these two versions. However, I am very suspicious of this "Improvement and fix" listed as part of build 17763.832, available Oct 15, 2019

Addresses an issue in which files that are stored in a Cluster Shared Volume (CSV) with an alternate data stream are still present after you try to delete them. You may also receive an "access is denied" message on the next try to access or delete the files.

我不确定为什么特定于 CSV 的更改会影响我的系统,但描述与我看到的更改完全匹配。


关于具体的代码,原来return "FileStream" 从来没有在我们的代码中使用过。相反,我们依赖于 IDisposable 接口,在 "critical section" 完成时关闭流,并解锁共享文件。

从技术上讲这是一个重大变化,我现在执行以下操作:

  1. 创建具有独占句柄的锁文件
  2. Return 一个实现了 IDisposable 的新对象
  3. 等到一次性对象被释放,然后关闭流并尝试删除文件
// ...
    public static IDisposable OpenAsLock(string path)
    {
        var stream = TranslateIOExceptions(() => System.IO.File.Open(path, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write, System.IO.FileShare.None));
        return new FileBasedLock(stream, path);
    }
// ...

internal class FileBasedLock : IDisposable
{
    public FileBasedLock(FileStream stream, string path)
    {
        Stream = stream ?? throw new System.ArgumentNullException(nameof(stream));
        Path = path ?? throw new System.ArgumentNullException(nameof(path));
    }

    public FileStream Stream { get; }
    public string Path { get; }
    public void Dispose()
    {
        Stream.Close();
        try { File.Delete(Path); }
        catch (IOException) { }
    }
}