c# - FileOptions.DeleteOnClose Windows 是特定的吗?

标签 c# file .net-core cross-platform

我正在尝试使用 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 是跨平台的,我希望在释放所有句柄时删除文件,但文件仍然存在。

最佳答案

阅读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
}

以上片段来自lines 261-269 of src/libraries/System.Private.CoreLib/src/System/IO/FileStream.Unix.csFileStream.Dispose 的一部分实现。

我创建了一个 Gist with the following test code :

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 的系统上不会被删除。

关于c# - FileOptions.DeleteOnClose Windows 是特定的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57176254/

相关文章:

c# - 面板滚动重置中的 DataGridView

c# - 在 C# 中使用 Linq 开始从 excel 的特定行读取数据

c++ - 文件 I/O 与 TCP 套接字,同一机器内数据传输哪个更快?

c# - 适用于 .NET Core 的 Windows 和 Linux 之间的编码(marshal)处理有何不同?

C#在dll中调用go函数,并且在.Net Core中运行,go分配的非托管内存会被垃圾收集吗?

.net-core - Serilog 命名连接字符串

c# - 找不到授权级别

c - C 中的字节蚕食

php - 从文本文件中获取随机行

c# - 使用 HttpClient 进行异步文件下载