Se si sta tentando di eliminare ricorsivamente la directory a
e la directory a\b
è aperta in Explorer, b
verrà eliminata ma verrà visualizzato l'errore "directory non vuota" a
anche se è vuota quando si va a cercare. La directory corrente di qualsiasi applicazione (incluso Explorer) mantiene un handle per la directory . Quando chiami Directory.Delete(true)
, cancella dal basso verso l'alto:, b
quindi a
. Se b
è aperto in Explorer, Explorer rileverà la cancellazione di b
, cambierà directory verso l'alto cd ..
e ripulirà gli handle aperti. Poiché il file system funziona in modo asincrono, l' Directory.Delete
operazione non riesce a causa di conflitti con Explorer.
Soluzione incompleta
Inizialmente ho pubblicato la seguente soluzione, con l'idea di interrompere il thread corrente per consentire a Explorer di rilasciare l'handle della directory.
// incomplete!
try
{
Directory.Delete(path, true);
}
catch (IOException)
{
Thread.Sleep(0);
Directory.Delete(path, true);
}
Questo funziona solo se la directory aperta è il figlio immediato della directory che si sta eliminando. Se a\b\c\d
è aperto in Explorer e lo usi su a
, questa tecnica fallirà dopo l'eliminazione d
e c
.
Una soluzione leggermente migliore
Questo metodo gestirà la cancellazione di una struttura di directory profonda anche se una delle directory di livello inferiore è aperta in Explorer.
/// <summary>
/// Depth-first recursive delete, with handling for descendant
/// directories open in Windows Explorer.
/// </summary>
public static void DeleteDirectory(string path)
{
foreach (string directory in Directory.GetDirectories(path))
{
DeleteDirectory(directory);
}
try
{
Directory.Delete(path, true);
}
catch (IOException)
{
Directory.Delete(path, true);
}
catch (UnauthorizedAccessException)
{
Directory.Delete(path, true);
}
}
Nonostante il lavoro extra di ricorrere da soli, dobbiamo ancora gestire UnauthorizedAccessException
ciò che può accadere lungo la strada. Non è chiaro se il primo tentativo di eliminazione stia aprendo la strada per il secondo, riuscito, o se è semplicemente il ritardo temporale introdotto dal lancio / cattura di un'eccezione che consente al file system di recuperare.
Potresti essere in grado di ridurre il numero di eccezioni generate e rilevate in condizioni tipiche aggiungendo Thread.Sleep(0)
a all'inizio del try
blocco. Inoltre, sussiste il rischio che, sotto un carico pesante del sistema, si possano volare entrambi i Directory.Delete
tentativi e fallire. Considera questa soluzione un punto di partenza per una più robusta cancellazione ricorsiva.
Risposta generale
Questa soluzione risolve solo le peculiarità dell'interazione con Windows Explorer. Se si desidera un'operazione di eliminazione solida, una cosa da tenere a mente è che qualsiasi cosa (scanner antivirus, qualunque cosa) potrebbe avere un controllo aperto su ciò che si sta tentando di eliminare, in qualsiasi momento. Quindi devi riprovare più tardi. Quanto più tardi e quante volte si tenta, dipende da quanto sia importante che l'oggetto venga eliminato. Come indica MSDN ,
Il robusto codice di iterazione dei file deve tenere conto di molte complessità del file system.
Questa dichiarazione innocente, fornita solo con un link alla documentazione di riferimento NTFS, dovrebbe farti alzare i capelli.
( Modifica : molto. Questa risposta originariamente aveva solo la prima soluzione incompleta.)