'How do I automatically delete temp files in C#?

What's a good way to ensure that a temp file is deleted if my application closes or crashes? Ideally, I would like to obtain a temp file, use it, and then forget about it.

Right now, I keep a list of my temp files and delete them with an EventHandler that's triggered on Application.ApplicationExit.

Is there a better way?



Solution 1:[1]

Consider using the FileOptions.DeleteOnClose flag:

using (FileStream fs = new FileStream(Path.GetTempFileName(),
       FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None,
       4096, FileOptions.RandomAccess | FileOptions.DeleteOnClose))
{
    // temp file exists
}

// temp file is gone

Solution 2:[2]

You could P/Invoke CreateFile and pass the FILE_FLAG_DELETE_ON_CLOSE flag. This tells Windows to delete the file once all handles are closed. See also: Win32 CreateFile docs.

Solution 3:[3]

I would use the .NET TempFileCollection class, as it's built-in, available in old versions of .NET, and implements the IDisposable interface and thus cleans up after itself if used e.g. in conjunction with the "using" keyword.

Here's an example that extracts text from an embedded resource (added via the projects property pages -> Resources tab as described here: How to embed a text file in a .NET assembly?, then set to "EmbeddedResource" in the embedded file's property settings).

    // Extracts the contents of the embedded file, writes them to a temp file, executes it, and cleans up automatically on exit.
    private void ExtractAndRunMyScript()
    {
        string vbsFilePath;

        // By default, TempFileCollection cleans up after itself.
        using (var tempFiles = new System.CodeDom.Compiler.TempFileCollection())
        {
            vbsFilePath= tempFiles.AddExtension("vbs");

            // Using IntelliSense will display the name, but it's the file name
            // minus its extension.
            System.IO.File.WriteAllText(vbsFilePath, global::Instrumentation.Properties.Resources.MyEmbeddedFileNameWithoutExtension);

            RunMyScript(vbsFilePath);
        }

        System.Diagnostics.Debug.Assert(!File.Exists(vbsFilePath), @"Temp file """ + vbsFilePath+ @""" has not been deleted.");
    }

Solution 4:[4]

I use a more reliable solution:

using System.IO;
using System.Reflection;
 
namespace Helpers
{
    public static partial class TemporaryFiles
    {
        private const string UserFilesListFilenamePrefix = ".used-temporary-files.txt";
        static private readonly object UsedFilesListLock = new object();
 
        private static string GetUsedFilesListFilename()
        {
            return Assembly.GetEntryAssembly().Location + UserFilesListFilenamePrefix;
        }
 
        private static void AddToUsedFilesList(string filename)
        {
            lock (UsedFilesListLock)
            {
                using (var writer = File.AppendText(GetUsedFilesListFilename()))
                    writer.WriteLine(filename);
            }
        }
 
        public static string UseNew()
        {
            var filename = Path.GetTempFileName();
            AddToUsedFilesList(filename);
            return filename;
        }
 
        public static void DeleteAllPreviouslyUsed()
        {
            lock (UsedFilesListLock)
            {
                var usedFilesListFilename = GetUsedFilesListFilename();
 
                if (!File.Exists(usedFilesListFilename))
                    return;
 
                using (var listFile = File.Open(usedFilesListFilename, FileMode.Open))
                {
                    using (var reader = new StreamReader(listFile))
                    {
                        string tempFileToDelete;
                        while ((tempFileToDelete = reader.ReadLine()) != null)
                        {
                            if (File.Exists(tempFileToDelete))
                                File.Delete(tempFileToDelete);
                        }
                    }
                }
 
                // Clean up
                using (File.Open(usedFilesListFilename, FileMode.Truncate)) { }
            }
        }
    }
}

Every time you need temporary file use:

var tempFile = TemporaryFiles.UseNew();

To be sure all temporary files are deleted after application closes or crashes put

TemporaryFiles.DeleteAllPreviouslyUsed();

at start of the application.

Solution 5:[5]

It's nice to see that you want to be responsible, but if the files aren't huge (>50MB), you would be in line with everyone (MS included) in leaving them in the temp directory. Disk space is abundant.

As csl posted, GetTempPath is the way to go. Users who are short on space will be able to run disk cleanup and your files (along with everyone else's) will be cleaned up.

Solution 6:[6]

I'm not primarily a C# programmer, but in C++ I'd use RAII for this. There are some hints on using RAII-like behaviour in C# online, but most seem to use the finalizer — which is not deterministic.

I think there are some Windows SDK functions to create temporary files, but don't know if they are automatically deleted on program termination. There is the GetTempPath function, but files there are only deleted when you log out or restart, IIRC.

P.S. The C# destructor documentation says you can and should release resources there, which I find a bit odd. If so, you could simply delete the temp file in the destructor, but again, this might not be completely deterministic.

Solution 7:[7]

You could launch a thread on startup that will delete files that exist when they "shouldn't" to recover from your crash.

Solution 8:[8]

If you're building a Windows Forms Application, you can use this code:

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        File.Delete("temp.data");
    }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 piedar
Solution 2 David Grant
Solution 3 Community
Solution 4
Solution 5 Pang
Solution 6 Pang
Solution 7 Austin Salonen
Solution 8 Zach