删除文件的行为是否在Windows上用FileShare.Delete打开



我们已经使用以下代码好几年了。

/// <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关闭。该技术被用作协作并发锁的一部分。

我发现了许多其他问题,这些问题让我认为过去的行为就像评论所描述的那样:文件一直保留在原地,直到返回的文件流关闭。

我们能在Windows中删除打开的文件吗?

使用FileShare.Delete是否会导致UnauthorizedAccessException?

然而,作为调查的一部分,我发现Windows并没有这样的行为。相反,一旦调用file.Delete,文件就会被删除。我还试图重现汉斯在上述链接中提出的错误,但没有成功。

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版本比我的开发机器旧。

  • 构建17134.1304肯定有旧的行为
  • 建造18363.657肯定有新的行为

我查看了构建版本的列表,不幸的是,这两个版本之间有二十多个版本。然而,我对这个"改进和修复"非常怀疑,它被列为构建17763.832的一部分,于2019年10月15日提供

解决存储在群集中的文件共享的问题具有备用数据流的卷(CSV(在您之后仍然存在尝试删除它们。您还可能收到"访问被拒绝"的消息在下一次尝试访问或删除文件。

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


关于特定的代码,我们的代码中从未使用过返回"FileStream"。相反,我们依赖IDisposable接口,在"关键部分"完成时关闭流,并解锁共享文件。

从技术上讲,这是一个突破性的改变,我现在做以下事情:

  1. 使用独占句柄创建锁定文件
  2. 返回实现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) { }
}
}

最新更新