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?
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.
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
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 .
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.");
}
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.
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.
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.
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.
si vous construisez une application Windows Forms, vous pouvez utiliser ce code:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
File.Delete("temp.data");
}