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

Nic*_*ick 6 c# windows

我一直在各地搜索,我似乎无法在任何地方找到这样的选项 - 使用GetTempFileName创建的临时文件似乎在应用程序终止后留下.

我该怎么做呢?

Sco*_*ain 21

在创建文件时使用 FileOptions.DeleteOnClose

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

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

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

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

更新:如果您有断电,您仍然会在磁盘上有一个文件,但如果您的程序被End Task强行关闭,该文件仍将被删除.删除是在内核级别而不是应用程序级别处理的.一旦文件的最后一个句柄被关闭,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);
}
Run Code Online (Sandbox Code Playgroud)

上面的代码是在浏览器中编写的,因此可能包含一两个错误,但它会得到一般的想法.

UPDATE2:即使断电也可以删除文件的一件事是使用WinAPI调用MoveFileEx,该调用可以选择在下次重启时使用MOVEFILE_DELAY_UNTIL_REBOOT标志删除文件并传递IntPtr.ZerolpNewFileName.