Comment supprimer automatiquement les fichiers tempfiles en c#?

Quelle est la bonne façon de s'assurer qu'un fichier temporaire est supprimé si mon application se ferme ou s'écrase? Idéalement, je souhaiterais obtenir un fichier temporaire, l'utiliser et puis l'oublier.

en ce moment je garde une liste de mes fichiers tempfiles et je les efface avec un eventhandler qui se déclenche lors de l'Application.ApplicationExit.

y a-t-il un meilleur moyen?

48
demandé sur Kev 2008-12-30 15:20:17

9 réponses

Rien n'est garanti que si le processus est tué prématurément, cependant, j'utilise " using " pour ce faire..

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

maintenant que le TempFile est éliminé ou les déchets-recueilli le fichier est supprimé (si possible). Vous pouvez évidemment l'utiliser aussi étroitement que vous le souhaitez, ou dans une collection quelque part.

68
répondu Marc Gravell 2008-12-31 11:17:51

envisagez d'utiliser les options FileOptions.Drapeau DeleteOnClose:

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
48
répondu DanW 2016-07-28 22:43:08

on pourrait P/Invoke CreateFile et passer à la FILE_FLAG_DELETE_ON_CLOSE pavillon. Cela indique à Windows de supprimer le fichier une fois que toutes les poignées sont fermées. Voir aussi: Win32 CreateFile docs .

18
répondu David Grant 2008-12-30 14:45:40

j'utiliserais la classe .NET TempFileCollection , car elle est intégrée, disponible dans les anciennes versions de .NET, et implémente l'interface IDisposable et donc nettoie après elle-même si elle est utilisée par exemple en conjonction avec le mot-clé "using" .

voici un exemple qui extrait du texte d'une ressource intégrée (ajouté via l'onglet Propriétés des projets -> ressources comme décrit ici: comment intégrer un fichier texte dans un assemblage .NET? , puis réglé sur "EmbeddedResource" dans les paramètres de propriétés du fichier intégré).

    // 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.");
    }
4
répondu user3454591 2017-05-23 11:46:51

Je ne suis pas principalement un programmeur C#, mais en C++ j'utiliserais RAII pour cela. Il y a quelques conseils sur l'utilisation du comportement de type RAII dans C# en ligne, mais la plupart semblent utiliser le finalizer-qui n'est pas déterministe.

je pense qu'il y a certaines fonctions SDK de Windows pour créer des fichiers temporaires, mais je ne sais pas si elles sont automatiquement supprimées à la fin du programme. Il y a la fonction GetTempPath , mais les fichiers ne sont supprimés que lorsque vous vous déconnectez ou redémarrez, IIRC.

P.S. la c # destructor documentation dit que vous pouvez et devez libérer des ressources là-bas, ce que je trouve un peu bizarre. Si oui, vous pouvez simplement supprimer le fichier temporaire dans le destructeur, mais encore une fois, cela peut ne pas être complètement déterministe.

3
répondu csl 2008-12-30 12:46:43

c'est agréable de voir que vous voulez être responsable, mais si les fichiers ne sont pas énormes (>50Mo) vous seriez en ligne avec tout le monde (MS inclus) en les laissant dans le répertoire temp. L'espace disque est abondante.

comme csl a posté, le GetTempPath est la voie à suivre. Les utilisateurs qui manquent d'espace seront en mesure d'exécuter le nettoyage de disque et vos fichiers (ainsi que ceux de tout le monde) seront nettoyés.

3
répondu StingyJack 2008-12-30 13:10:38

j'utilise une solution plus fiable:

using System.IO;
using System.Reflection;

namespace Konard.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)) { }
            }
        }
    }
}

chaque fois que vous avez besoin d'une utilisation temporaire de fichier:

var tempFile = TemporaryFiles.UseNew();

pour être sûr que tous les fichiers temporaires sont supprimés après la fermeture de l'application ou les plantages mettre

TemporaryFiles.DeleteAllPreviouslyUsed();

au début de la demande.

2
répondu Konard 2014-11-19 13:54:00

vous pouvez lancer un thread sur le démarrage qui supprimera les fichiers qui existent alors qu'ils" ne devraient pas " pour récupérer de votre plantage.

0
répondu Austin Salonen 2008-12-30 16:54:22

si vous construisez une application Windows Forms, vous pouvez utiliser ce code:

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        File.Delete("temp.data");
    }
-2
répondu Zach 2015-07-15 18:27:19