首页 > 解决方案 > FileOptions.DeleteOnClose Windows 是特定的吗?

问题描述

我正在尝试使用 FileStream 和 FileOptions.DeleteOnClose 创建一个临时文件。我在关闭流时看到了预期的行为,但是如果抛出异常,则不会删除文件。我不能使用using,因为流的关闭是由 FileStreamResult 处理的。我知道在 Windows 上它由 winapi 标志 FILE_FLAG_DELETE_ON_CLOSE 处理,但我不知道这是否/如何适用于 .NET Core 应用程序上的其他平台。

我已经尝试围绕它包装一个 try-catch 以在错误的情况下手动处理流,这确实有效,但应该是不必要的,因为一旦释放所有句柄,文件就会被删除。

            const FileOptions fileOptions =
                FileOptions.Asynchronous |
                FileOptions.DeleteOnClose |
                FileOptions.Encrypted |
                FileOptions.SequentialScan;

            var fileStream = new FileStream(
                Path.GetRandomFileName(),
                FileMode.Create,
                FileAccess.ReadWrite,
                FileShare.None,
                4096,
                fileOptions);

如果 FileOptions.DeleteOnClose 是跨平台的,我希望在释放所有句柄时删除该文件,但该文件仍然存在。

标签: c#file.net-corecross-platform

解决方案


阅读 的源代码src/libraries/System.Private.CoreLib/src/System/IO/FileStream.Unix.cs,在处理时似乎FileOptions.DeleteOnClose在 *nix 平台上受到尊重和效仿:

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

// ...

// If DeleteOnClose was requested when constructed, delete the file now.
// (Unix doesn't directly support DeleteOnClose, so we mimic it here.)
if (_path != null && (_options & FileOptions.DeleteOnClose) != 0)
{
    // Since we still have the file open, this will end up deleting
    // it (assuming we're the only link to it) once it's closed, but the
    // name will be removed immediately.
    Interop.Sys.Unlink(_path); // ignore errors; it's valid that the path may no longer exist
}

上面的代码片段来自第 261-269 行,src/libraries/System.Private.CoreLib/src/System/IO/FileStream.Unix.cs也是实现的一部分FileStream.Dispose

使用以下测试代码创建了一个要点

using System.IO;

var fileName = Path.GetRandomFileName();
Console.WriteLine($"File name: {fileName}");
Console.WriteLine($"Exists? {File.Exists(fileName)}");
using (var fs = File.Create(fileName, 4096, FileOptions.DeleteOnClose))
    Console.WriteLine($"Exists? {File.Exists(fileName)}");
Console.WriteLine($"Exists? {File.Exists(fileName)}");

然后使用 Docker 在 Linux 上使用 .NET Core SDK 3.1 进行测试,如下所示:

> docker run --rm -it mcr.microsoft.com/dotnet/core/sdk:3.1
> root@86a890d817b7:/# dotnet tool install dotnet-script --version 0.53.0 --tool-path /usr/bin
You can invoke the tool using the following command: dotnet-script
Tool 'dotnet-script' (version '0.53.0') was successfully installed.
> root@86a890d817b7:/# dotnet script https://gist.github.com/atifaziz/2a0291a076c77e197d849eab7c049b1b/raw/9b5a08c0ffd45e09eac19325445b9fbdf799e10c/test.csx
File name: hrylnqis.nxv
Exists? False
Exists? True
Exists? False

输出似乎确认FileOptions.DeleteOnClose按预期工作,因此,不,根据您的问题,它不是特定于 Windows 的。

但请记住,由于DeleteOnClose是为(某些定义的)Unix 模拟的,它没有与 Windows 相同的强大保证。例如,如果进程崩溃或粗暴地退出,Environment.Exit则该文件将在 Windows 上被删除,但在基于 Unix 的系统上不会被删除。


推荐阅读