Domanda

Quali sono un buon modo per garantire che un file temporaneo venga eliminato se la mia applicazione si chiude o si arresta in modo anomalo? Idealmente, vorrei ottenere un tempfile, usarlo e poi dimenticarlo.

In questo momento tengo un elenco dei miei tempfile e li elimino con un gestore di eventi che si attiva su Application.ApplicationExit.

C'è un modo migliore?

È stato utile?

Soluzione

Nulla è garantito se il processo viene interrotto prematuramente, tuttavia, utilizzo " utilizzando " per fare questo ..

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

Ora quando il TempFile viene eliminato o immesso nella spazzatura, il file viene eliminato (se possibile). Ovviamente potresti usarlo nel modo che preferisci o in una raccolta da qualche parte.

Altri suggerimenti

Valuta l'utilizzo del flag FileOptions.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

Potresti P / Invoke CreateFile e passa il flag FILE_FLAG_DELETE_ON_CLOSE . Ciò indica a Windows di eliminare il file una volta chiusi tutti gli handle. Vedi anche: Win32 CreateFile docs .

Vorrei utilizzare la classe .NET TempFileCollection , poiché è integrata, disponibile nelle vecchie versioni di .NET e implementa l'interfaccia IDisposable e quindi pulisco dopo se usato ad es insieme alla parola chiave " utilizzando " .

Ecco un esempio che estrae il testo da una risorsa incorporata (aggiunta tramite le pagine delle proprietà dei progetti - > scheda Risorse come descritto qui: Come incorporare un file di testo in un assembly .NET? , quindi impostare su " EmbeddedResource " nel impostazioni di proprietà del file incorporato).

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

Non sono principalmente un programmatore C #, ma in C ++ userò RAII per questo. Ci sono alcuni suggerimenti sull'uso del comportamento simile a RAII in C # online, ma la maggior parte sembra utilizzare il finalizzatore & # 8212; che non è deterministico.

Penso che ci siano alcune funzioni di Windows SDK per creare file temporanei, ma non so se vengono automaticamente cancellati al termine del programma. Esiste la funzione GetTempPath , ma i file vengono eliminati solo quando ti disconnetti o riavvii, IIRC.

P.S. La Documentazione del distruttore C # dice che puoi e dovresti rilasciare risorse lì, che Trovo un po 'strano. In tal caso, potresti semplicemente eliminare il file temporaneo nel distruttore, ma di nuovo, questo potrebbe non essere completamente deterministico.

È bello vedere che vuoi essere responsabile, ma se i file non sono enormi (> 50 MB) saresti in linea con tutti (MS incluso) lasciandoli nella directory temp. Lo spazio su disco è abbondante.

Come csl ha pubblicato, GetTempPath è la strada da percorrere. Gli utenti che hanno poco spazio saranno in grado di eseguire la pulizia del disco e i tuoi file (insieme a quelli di tutti gli altri) verranno ripuliti.

Uso una soluzione più affidabile:

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

Ogni volta che è necessario l'uso temporaneo dei file:

var tempFile = TemporaryFiles.UseNew();

Per essere sicuri che tutti i file temporanei vengano eliminati dopo la chiusura o l'arresto anomalo dell'applicazione

TemporaryFiles.DeleteAllPreviouslyUsed();

all'inizio dell'applicazione.

Potresti lanciare un thread all'avvio che eliminerà i file esistenti quando " non dovrebbero " per riprendersi dal tuo incidente.

Se stai creando un'applicazione Windows Form, puoi utilizzare questo codice:

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        File.Delete("temp.data");
    }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top