如何创建程序终止后自动删除的临时文件

本文关键字:删除 临时文件 终止 程序 何创建 创建 | 更新日期: 2023-09-27 18:30:08

我一直在到处搜索,但我似乎在任何地方都找不到这样的选项 - 一旦应用程序终止,使用 GetTempFileName 创建的临时文件似乎就会被留下。

我该怎么做?

如何创建程序终止后自动删除的临时文件

创建文件时,请使用FileOptions.DeleteOnClose

using (var fs = new FileStream(Path.GetTempFileName(), FileMode.Open, FileAccess.ReadWrite, FileShare.None, 4096, FileOptions.DeleteOnClose))
{
    // do your work here
}

关闭流后,文件将被删除。

如果您需要整个时间打开文件,您可以使用FileShare.ReadWrite | FileShare.Delete而不是FileShare.None打开流,然后在需要在整个程序中访问文件时再次打开相同的文件名。然后在退出程序时关闭流。

注意:您不一定需要显式关闭流,程序关闭的操作将关闭流并执行必要的清理以删除文件。如果您确实使用此方法,请确保只要程序处于活动状态,您就有对活动流的引用,否则 GC 可能会清理流并尽早删除文件。

更新:如果您断电,您仍然会在磁盘上有一个文件,但是如果您的程序被强制关闭并执行结束任务,该文件仍将被删除。删除操作在内核级别处理,而不是在应用程序级别处理。关闭文件的最后一个句柄后,Windows 本身就是删除文件的内容。

虽然您可能无法在断电时删除文件,但还有另一种选择可以最小化磁盘上留下的临时文件大小。这将需要你更深入地进行P/Invoke CreateFile。您可以使用一个标志FILE_ATTRIBUTE_TEMPORARY,它将告诉Windows不要刷新对磁盘的写入,如果可能的话,将它们保留在缓存中。使用此属性,文件可能会被留下,但文件大小可能为 0kB。

[DllImport("kernel32.dll", SetLastError = true, CharSet=CharSet.Unicode)]
static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess,
  uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition,
  uint dwFlagsAndAttributes, IntPtr hTemplateFile);
public const uint OPEN_EXISTING = 3
public const uint GENERIC_READ = 0x80000000;
public const uint GENERIC_WRITE = 0x40000000;
public const uint FILE_ATTRIBUTE_TEMPORARY = 0x100;
public const uint FILE_FLAG_DELETE_ON_CLOSE = 0x04000000;
public FileStream OpenTempFile()
{
    var path = Path.GetTempFileName();
    var handle = CreateFile(path, GENERIC_READ | GENERIC_WRITE, 0, IntPtr.Zero 
                           ,OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE
                           ,IntPtr.Zero);
    if (handle.IsInvalid)
    {
        Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
    }
    return new FileStream(handle, FileAccess.ReadWrite);
}

上面的代码是在浏览器中编写的,因此可能包含一两个错误,但它可以传达一般想法。

UPDATE2:即使断电,您也可以做的一件事是使用 WinAPI 调用MoveFileEx,该调用可以选择在下次重新启动时通过使用 MOVEFILE_DELAY_UNTIL_REBOOT 标志并将IntPtr.Zero传递给lpNewFileName来删除文件。