¿Cómo elimino automáticamente los archivos temporales en c#?


¿Cuál es una buena manera de garantizar que un archivo temporal se elimine si mi aplicación se cierra o se bloquea? Idealmente me gustaría obtener una tempfile, usarlo y luego olvidarse de él.

Ahora mismo guardo una lista de mis archivos temporales y los elimino con un eventhandler que se activa en la Aplicación.ApplicationExit.

Hay una manera mejor?

Author: Kev, 2008-12-30

9 answers

Nada está garantizado si el proceso se mata prematuramente, sin embargo, uso "using" para hacer esto..

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

Ahora, cuando el TempFile se elimina o se recolecta basura, el archivo se elimina (si es posible). Obviamente, podría usar esto tan estrechamente como desee, o en una colección en algún lugar.

 68
Author: Marc Gravell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-31 11:17:51

Considere usar las opciones de archivo.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
 48
Author: DanW,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-28 22:43:08

Podrías P/Invocar CreateFile y pase la bandera FILE_FLAG_DELETE_ON_CLOSE. Esto le dice a Windows que elimine el archivo una vez que todos los controladores estén cerrados. Véase también: Win32 CreateFile docs .

 18
Author: David Grant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-30 14:45:40

Usaría la clase.NET TempFileCollection, ya que está incorporada, disponible en versiones antiguas de. NET, e implementa la interfaz IDisposable y, por lo tanto, limpia después de sí misma si se usa, por ejemplo, junto con la palabra clave "using".

Aquí hay un ejemplo que extrae texto de un recurso incrustado (agregado a través de la propiedad páginas de proyectos -> Pestaña Recursos como se describe aquí: ¿Cómo incrustar un archivo de texto en un ensamblado. NET?, luego establezca "EmbeddedResource" en la configuración de propiedades del archivo incrustado).

    // 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
Author: user3454591,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:46:51

No soy principalmente un programador de C#, pero en C++ usaría RAII para esto. Hay algunas sugerencias sobre el uso de un comportamiento similar a RAII en C# en línea, pero la mayoría parecen usar el finalizer, que no es determinista.

Creo que hay algunas funciones del SDK de Windows para crear archivos temporales, pero no sé si se eliminan automáticamente al finalizar el programa. Existe la función GetTempPath , pero los archivos allí solo se eliminan cuando cierra la sesión o reinicia, IIRC.

P.d. La documentación de C# destructor dice que puede y debe liberar recursos allí, lo que me parece un poco extraño. Si es así, simplemente podría eliminar el archivo temporal en el destructor, pero de nuevo, esto podría no ser completamente determinista.

 3
Author: csl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-30 12:46:43

Es bueno ver que quieres ser responsable, pero si los archivos no son enormes (>50MB) estarías en línea con todos (MS incluido) al dejarlos en el directorio temporal. El espacio en disco es abundante.

Como csl publicó, el GetTempPath es el camino a seguir. Los usuarios que tienen poco espacio podrán ejecutar el liberador de espacio en disco y sus archivos (junto con los de todos los demás) se limpiarán.

 3
Author: StingyJack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-30 13:10:38

Utilizo una solución más 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)) { }
            }
        }
    }
}

Cada vez que necesite usar un archivo temporal:

var tempFile = TemporaryFiles.UseNew();

Para asegurarse de que todos los archivos temporales se eliminen después de que la aplicación se cierre o se bloquee, ponga

TemporaryFiles.DeleteAllPreviouslyUsed();

Al inicio de la aplicación.

 2
Author: Konard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-19 13:54:00

Puede iniciar un hilo al iniciar que eliminará los archivos que existen cuando "no deberían" para recuperarse de su bloqueo.

 0
Author: Austin Salonen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-30 16:54:22

Si está creando una aplicación de Windows Forms, puede usar este código:

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        File.Delete("temp.data");
    }
 -2
Author: Zach,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-15 18:27:19