Come posso eliminare automaticamente i tempfile in c #?
-
03-07-2019 - |
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?
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");
}