How do I automatically delete temp files in C#?

C#.NetTemporary Files

C# Problem Overview


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?

C# Solutions


Solution 1 - C#

Nothing is guaranteed if the process is killed prematurely, however, I use "using" to do this..

using System;
using System.IO;
sealed class TempFile : IDisposable
{
    string path;
    public TempFile() : this(System.IO.Path.GetTempFileName()) { }

    public TempFile(string path)
    {
        if (string.IsNullOrEmpty(path)) throw new ArgumentNullException("path");
        this.path = path;
    }
    public string Path
    {
        get
        {
            if (path == null) throw new ObjectDisposedException(GetType().Name);
            return path;
        }
    }
    ~TempFile() { Dispose(false); }
    public void Dispose() { Dispose(true); }
    private void Dispose(bool disposing)
    {
        if (disposing)
        {
            GC.SuppressFinalize(this);                
        }
        if (path != null)
        {
            try { File.Delete(path); }
            catch { } // best effort
            path = null;
        }
    }
}
static class Program
{
    static void Main()
    {
        string path;
        using (var tmp = new TempFile())
        {
            path = tmp.Path;
            Console.WriteLine(File.Exists(path));
        }
        Console.WriteLine(File.Exists(path));
    }
}

Now when the TempFile is disposed or garbage-collected the file is deleted (if possible). You could obviously use this as tightly-scoped as you like, or in a collection somewhere.

Solution 2 - C#

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 3 - C#

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 4 - C#

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: https://stackoverflow.com/questions/433171/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 5 - C#

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 6 - C#

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 - C#

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 8 - C#

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

Solution 9 - C#

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNifleView Question on Stackoverflow
Solution 1 - C#Marc GravellView Answer on Stackoverflow
Solution 2 - C#DanWView Answer on Stackoverflow
Solution 3 - C#David GrantView Answer on Stackoverflow
Solution 4 - C#user3454591View Answer on Stackoverflow
Solution 5 - C#KonardView Answer on Stackoverflow
Solution 6 - C#cslView Answer on Stackoverflow
Solution 7 - C#StingyJackView Answer on Stackoverflow
Solution 8 - C#Austin SalonenView Answer on Stackoverflow
Solution 9 - C#ZachView Answer on Stackoverflow