Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a temp file that is automatically deleted after the program terminates?

Tags:

c#

windows

I have been searching everywhere and I can't seem to find such an option anywhere – the temp files created using GetTempFileName seem to be left behind once the application terminates.

How do I do this?

like image 724
Nick Avatar asked Jan 13 '16 20:01

Nick


Video Answer


1 Answers

When creating the file use FileOptions.DeleteOnClose

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

Once the stream is closed the file will be deleted.

If you need the file open the entire time you can open the stream with FileShare.ReadWrite | FileShare.Delete instead of FileShare.None then open the same filename again when you need to access the file throughout the program. Then just close the stream as you quit the program.

NOTE: You don't necessarily need to explicitly close the stream, the act of your program closing will close the stream and do the necessary cleanup to delete the file. If you do go with this approach make sure you have a reference to the stream that is alive for as long as your program is alive or else the GC may cleanup the stream and delete the file early on you.

UPDATE: If you have a power loss you are still going to have a file on the disk, but if your program is forcefully closed with a End Task the file will still be deleted. The deletion is handled on the kernel level, not the application level. Once the last handle to the file is closed Windows itself is what deletes the file.

While you might not be able make the file deleted on a power loss there is another option to minimize the temporary file size on the disk that is left behind. This will require you to go a level deeper and P/Invoke CreateFile directly. There is a flag FILE_ATTRIBUTE_TEMPORARY you can use, what that will do is tell windows to not flush writes out to the disk and just keep them in the cache if possible. With this attribute the file may be left behind but there is a decent chance that the file may be 0kB in size.

[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);
}

The above code was written in the browser so may contain a error or two but it gets the general idea across.

UPDATE2: One thing you can do to delete the file even if the power is lost is use the WinAPI call MoveFileEx which has the option to delete a file on next reboot by using the MOVEFILE_DELAY_UNTIL_REBOOT flag and passing IntPtr.Zero to lpNewFileName.

like image 74
Scott Chamberlain Avatar answered Oct 16 '22 14:10

Scott Chamberlain