Come eliminare tutti i file e le cartelle in una directory?


663

Utilizzando C #, come posso eliminare tutti i file e le cartelle da una directory, ma mantenere comunque la directory principale?


11
Cosa sarebbe bello se DirectoryInfo avesse un metodo come .Clean ();
JL.

6
o .DeleteFolders e metodi DeleteFiles.
JL.

18
Devi essere consapevole del fatto che le tue eliminazioni potrebbero facilmente generare un'eccezione se un file è bloccato (o se non hai i diritti). Vedere FileInfo.Delete per un elenco delle eccezioni.
Shane Courtrille,

Risposte:


834
System.IO.DirectoryInfo di = new DirectoryInfo("YourPath");

foreach (FileInfo file in di.GetFiles())
{
    file.Delete(); 
}
foreach (DirectoryInfo dir in di.GetDirectories())
{
    dir.Delete(true); 
}

Se la tua directory può contenere molti file, EnumerateFiles()è più efficiente di GetFiles(), perché quando lo usi EnumerateFiles()puoi iniziare a enumerarlo prima che venga restituita l'intera raccolta, al contrario di GetFiles()dove devi caricare l'intera raccolta in memoria prima di iniziare a enumerarla. Vedi questa citazione qui :

Pertanto, quando si lavora con molti file e directory, EnumerateFiles () può essere più efficiente.

Lo stesso vale per EnumerateDirectories()e GetDirectories(). Quindi il codice sarebbe:

foreach (FileInfo file in di.EnumerateFiles())
{
    file.Delete(); 
}
foreach (DirectoryInfo dir in di.EnumerateDirectories())
{
    dir.Delete(true); 
}

Ai fini di questa domanda, non c'è davvero alcun motivo per usare GetFiles()e GetDirectories().


6
Che cos'è stackoverflow.com/questions/12415105/… "Quando si chiama Directory.Delete e un file è aperto in questo modo, Directory.Delete riesce a eliminare tutti i file ma quando Directory.Delete chiama RemoveDirectory una" directory non è vuota " viene generata un'eccezione perché esiste un file contrassegnato per l'eliminazione ma non effettivamente eliminato. "
Kiquenet,

74
DirectoryInfo è lento in quanto raccoglie molti più dati. A proposito: Directory.Delete(path, true)si occuperà di tutto :)
AcidJunkie

57
@AcidJunkie, Questo rimuoverà anche la directory in questione, mentre l'OP chiede espressamente di conservare la directory root.
Marc L.,

5
Nota che questo non funzionerà se qualcuno dei file è di sola lettura. È necessario rimuovere il flag di sola lettura prima di chiamare file.Delete().
Ben

8
Questo sembra non funzionare se le sottodirectory contengono file.
cdiggins,

174

Sì, questo è il modo corretto di farlo. Se stai cercando di darti una funzione "Clean" (o, come preferirei chiamarla, funzione "Empty"), puoi creare un metodo di estensione.

public static void Empty(this System.IO.DirectoryInfo directory)
{
    foreach(System.IO.FileInfo file in directory.GetFiles()) file.Delete();
    foreach(System.IO.DirectoryInfo subDirectory in directory.GetDirectories()) subDirectory.Delete(true);
}

Questo ti permetterà quindi di fare qualcosa come ..

System.IO.DirectoryInfo directory = new System.IO.DirectoryInfo(@"C:\...");

directory.Empty();

4
L'ultima riga dovrebbe essere subDirectory.Delete (true) invece di directory.Delete (true). Ho appena tagliato e incollato il codice e ha eliminato la directory principale stessa. Grazie per il codice è fantastico!
Aximili,

26
nota che Emptyesiste già in C #, per string. Se vedessi qualcos'altro chiamato Emptysarei sorpreso se modificasse l'oggetto (o il filesystem) invece di darmi un messaggio boolche dice se è vuoto o no. Per questo motivo, vorrei andare con il nome Clean.
Predefinito

5
@Default: non credo che il fatto che un tipo abbia già una proprietà dovrebbe avere qualche influenza sul fatto che un altro tipo (completamente non correlato) debba averlo; e la convenzione per le proprietà e le funzioni che indicano lo stato per le parole che possono anche essere verbi è di prefissarle Is(cioè IsEmptypiuttosto che Empty).
Adam Robinson,

3
@AdamRobinson Volevo solo prenderne nota. Per me , ciò che Microsoft ha nel loro codice ha qualche rilevanza. Ma è per tutti interpretare :)
Predefinito

4
@simonhaines: il punto della domanda era svuotare la directory (cioè eliminare tutto al suo interno ), non cancellare la directory stessa.
Adam Robinson,

77

Il seguente codice cancellerà la cartella in modo ricorsivo:

private void clearFolder(string FolderName)
{
    DirectoryInfo dir = new DirectoryInfo(FolderName);

    foreach(FileInfo fi in dir.GetFiles())
    {
        fi.Delete();
    }

    foreach (DirectoryInfo di in dir.GetDirectories())
    {
        clearFolder(di.FullName);
        di.Delete();
    }
}

Ha funzionato per me, mentre Directory.Delete (percorso, vero); si è lamentato del fatto che la cartella non fosse empy
Jack Griffin il

40
 new System.IO.DirectoryInfo(@"C:\Temp").Delete(true);

 //Or

 System.IO.Directory.Delete(@"C:\Temp", true);

1
La seconda opzione, Directory.Delete (String, Boolean) ha funzionato per me.
Stephen MacDougall

15
Ciò elimina la directory principale, dove l'OP ha chiesto espressamente di conservarla.
Marc L.,

2
Deleteverrà lanciato se la directory non esiste, quindi sarebbe più sicuro fare Directory.Existsprima un controllo.
James,

1
@James Directory.Existsnon è abbastanza; dopo il controllo, un altro thread potrebbe aver rinominato o rimosso la directory. È più sicuro try-catch.
andre_ss6,

2
@Marv Attento semplicemente aggiungendo un Directory.Createperché Directory.Deletepurtroppo il ricorsivo non è garantito per essere sincrono ..
Andrew Hanlon

38

Possiamo anche mostrare amore per LINQ :

using System.IO;
using System.Linq;

var directory = Directory.GetParent(TestContext.TestDir);

directory.EnumerateFiles()
    .ToList().ForEach(f => f.Delete());

directory.EnumerateDirectories()
    .ToList().ForEach(d => d.Delete(true));

Nota che la mia soluzione qui non è performante, perché sto usando Get*().ToList().ForEach(...)quale genera lo stesso IEnumerabledue volte. Uso un metodo di estensione per evitare questo problema:

using System.IO;
using System.Linq;

var directory = Directory.GetParent(TestContext.TestDir);

directory.EnumerateFiles()
    .ForEachInEnumerable(f => f.Delete());

directory.EnumerateDirectories()
    .ForEachInEnumerable(d => d.Delete(true));

Questo è il metodo di estensione:

/// <summary>
/// Extensions for <see cref="System.Collections.Generic.IEnumerable"/>.
/// </summary>
public static class IEnumerableOfTExtensions
{
    /// <summary>
    /// Performs the <see cref="System.Action"/>
    /// on each item in the enumerable object.
    /// </summary>
    /// <typeparam name="TEnumerable">The type of the enumerable.</typeparam>
    /// <param name="enumerable">The enumerable.</param>
    /// <param name="action">The action.</param>
    /// <remarks>
    /// “I am philosophically opposed to providing such a method, for two reasons.
    /// …The first reason is that doing so violates the functional programming principles
    /// that all the other sequence operators are based upon. Clearly the sole purpose of a call
    /// to this method is to cause side effects.”
    /// —Eric Lippert, “foreach” vs “ForEach” [http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx]
    /// </remarks>
    public static void ForEachInEnumerable<TEnumerable>(this IEnumerable<TEnumerable> enumerable, Action<TEnumerable> action)
    {
        foreach (var item in enumerable)
        {
            action(item);
        }
    }
}

1
E se stai cercando di eliminare anche le sottodirectory, foreach (var dir in info.GetDirectories("*", SearchOption.AllDirectories).OrderByDescending(dir => dir.FullName.Length)) dir.Delete();potrebbe essere utile.
Warty,

1
Se ti piacciono le prestazioni, considera l'utilizzo directory.EnumerateFiles()e directory.EnumerateDirectories()invece dei directory.Get*()metodi.
Tinister,

1
Divertente, la mia IEnumerable<T>.ForEach()estensione ha un commento XML sommario, "Violazione! Violazione! Impuro!".
Marc L.

Ehi qual è il secondo motivo? Il 3? Eccetera.?
Bill Roberts,

lol @RASX - ti sta parlando: "Se non sei d'accordo con queste obiezioni filosofiche e trovi valore pratico in questo schema, vai avanti e scrivi tu stesso questa banale lezione da solo".
Bill Roberts,

37

Il modo più semplice:

Directory.Delete(path,true);  
Directory.CreateDirectory(path);

Tenere presente che ciò potrebbe cancellare alcune autorizzazioni per la cartella.


9
tieni presente che ciò rimuoverà tutte le autorizzazioni speciali del percorso
Matthew Lock,

6
Devi aggiungere il timeout tra queste due azioni. prova ad eseguire questo codice e otterrai Eccezione: while (true) {Directory.Delete (@ "C: \ Myfolder", true); Directory.CreateDirectory (@ "C: \ MyFolder"); }
RcMan

31
private void ClearFolder(string FolderName)
{
    DirectoryInfo dir = new DirectoryInfo(FolderName);

    foreach(FileInfo fi in dir.GetFiles())
    {
        try
        {
            fi.Delete();
        }
        catch(Exception) { } // Ignore all exceptions
    }

    foreach(DirectoryInfo di in dir.GetDirectories())
    {
        ClearFolder(di.FullName);
        try
        {
            di.Delete();
        }
        catch(Exception) { } // Ignore all exceptions
    }
}

Se sai che non ci sono sottocartelle, qualcosa del genere potrebbe essere la più semplice:

    Directory.GetFiles(folderName).ForEach(File.Delete)

Ho usato questa funzione per cancellare la cartella temp del sistema. Ho appena aggiunto try-catch attorno a Delete () e IsReadOnly per ignorare tutte le eccezioni, e ha funzionato.
humbads

@humbads, puoi aggiornare questa risposta o inserire qui il codice e aggiornerò con le tue modifiche?
zumalifeguard

13
System.IO.Directory.Delete(installPath, true);
System.IO.Directory.CreateDirectory(installPath);

3
come sopra: tenere presente che ciò rimuoverà tutte le autorizzazioni speciali del percorso.
hB0

8

Ogni metodo che ho provato, hanno fallito ad un certo punto con errori System.IO. Il seguente metodo funziona sicuramente, anche se la cartella è vuota o no, sola lettura o no, ecc.

ProcessStartInfo Info = new ProcessStartInfo();  
Info.Arguments = "/C rd /s /q \"C:\\MyFolder"";  
Info.WindowStyle = ProcessWindowStyle.Hidden;  
Info.CreateNoWindow = true;  
Info.FileName = "cmd.exe";  
Process.Start(Info); 

1
Preferisco sempre rd / s / q + mkdir quando si tratta di svuotare le directory.
Dawid Ohia,

7
Questa non è una soluzione multipiattaforma. I sistemi simili a Unix non hanno chiaramente cmd.exe, non eseguono nemmeno file .exe. C # non è solo Windows, c'è anche Mono, che è multipiattaforma.
Visualizza nome

1
@SargeBorsch non c'erano requisiti multipiattaforma nella domanda ed essendo C # è molto probabile che la soluzione verrà utilizzata per Windows. Sembra essere l'unica risposta che non utilizza le funzioni .NET, quindi è piuttosto preziosa come alternativa.
Alex Pandrea,

7

Ecco lo strumento con cui ho finito dopo aver letto tutti i post. Lo fa

  • Elimina tutto ciò che può essere eliminato
  • Restituisce false se alcuni file rimangono nella cartella

Ha a che fare con

  • File di sola lettura
  • Ritardo alla cancellazione
  • File bloccati

Non utilizza Directory.Delete perché il processo viene interrotto in caso di eccezione.

    /// <summary>
    /// Attempt to empty the folder. Return false if it fails (locked files...).
    /// </summary>
    /// <param name="pathName"></param>
    /// <returns>true on success</returns>
    public static bool EmptyFolder(string pathName)
    {
        bool errors = false;
        DirectoryInfo dir = new DirectoryInfo(pathName);

        foreach (FileInfo fi in dir.EnumerateFiles())
        {
            try
            {
                fi.IsReadOnly = false;
                fi.Delete();

                //Wait for the item to disapear (avoid 'dir not empty' error).
                while (fi.Exists)
                {
                    System.Threading.Thread.Sleep(10);
                    fi.Refresh();
                }
            }
            catch (IOException e)
            {
                Debug.WriteLine(e.Message);
                errors = true;
            }
        }

        foreach (DirectoryInfo di in dir.EnumerateDirectories())
        {
            try
            {
                EmptyFolder(di.FullName);
                di.Delete();

                //Wait for the item to disapear (avoid 'dir not empty' error).
                while (di.Exists)
                {
                    System.Threading.Thread.Sleep(10);
                    di.Refresh();
                }
            }
            catch (IOException e)
            {
                Debug.WriteLine(e.Message);
                errors = true;
            }
        }

        return !errors;
    }

6

Il seguente codice pulirà la directory, ma lascerà lì la directory root (ricorsiva).

Action<string> DelPath = null;
DelPath = p =>
{
    Directory.EnumerateFiles(p).ToList().ForEach(File.Delete);
    Directory.EnumerateDirectories(p).ToList().ForEach(DelPath);
    Directory.EnumerateDirectories(p).ToList().ForEach(Directory.Delete);
};
DelPath(path);

6

ero solito

Directory.GetFiles(picturePath).ToList().ForEach(File.Delete);

per eliminare la vecchia immagine e non ho bisogno di alcun oggetto in questa cartella


1
Non sono sicuro di aver bisogno di .ToList ()
Ben Power il

5

L'uso di soli metodi statici con File e Directory anziché FileInfo e DirectoryInfo funzionerà più velocemente. (vedi la risposta accettata in Qual è la differenza tra File e FileInfo in C #? ). Risposta mostrata come metodo di utilità.

public static void Empty(string directory)
{
    foreach(string fileToDelete in System.IO.Directory.GetFiles(directory))
    {
        System.IO.File.Delete(fileToDelete);
    }
    foreach(string subDirectoryToDeleteToDelete in System.IO.Directory.GetDirectories(directory))
    {
        System.IO.Directory.Delete(subDirectoryToDeleteToDelete, true);
    }
}

5
private void ClearFolder(string FolderName)
{
    DirectoryInfo dir = new DirectoryInfo(FolderName);

    foreach (FileInfo fi in dir.GetFiles())
    {
        fi.IsReadOnly = false;
        fi.Delete();
    }

    foreach (DirectoryInfo di in dir.GetDirectories())
    {
        ClearFolder(di.FullName);
        di.Delete();
    }
}

3
string directoryPath = "C:\Temp";
Directory.GetFiles(directoryPath).ToList().ForEach(File.Delete);
Directory.GetDirectories(directoryPath).ToList().ForEach(Directory.Delete);

Si è verificata un'eccezione di tipo 'System.IO.IOException' in mscorlib.dll ma non è stata gestita nel codice utente Ulteriori informazioni: La directory non è vuota.
kipusoep,

3

In Windows 7, se l'hai appena creato manualmente con Esplora risorse, la struttura delle directory è simile a questa:

C:
  \AAA
    \BBB
      \CCC
        \DDD

Ed eseguendo il codice suggerito nella domanda originale per pulire la directory C: \ AAA, la riga di.Delete(true) fallisce sempre con IOException "La directory non è vuota" quando si tenta di eliminare BBB. Probabilmente è a causa di qualche tipo di ritardo / memorizzazione nella cache in Esplora risorse.

Il seguente codice funziona in modo affidabile per me:

static void Main(string[] args)
{
    DirectoryInfo di = new DirectoryInfo(@"c:\aaa");
    CleanDirectory(di);
}

private static void CleanDirectory(DirectoryInfo di)
{
    if (di == null)
        return;

    foreach (FileSystemInfo fsEntry in di.GetFileSystemInfos())
    {
        CleanDirectory(fsEntry as DirectoryInfo);
        fsEntry.Delete();
    }
    WaitForDirectoryToBecomeEmpty(di);
}

private static void WaitForDirectoryToBecomeEmpty(DirectoryInfo di)
{
    for (int i = 0; i < 5; i++)
    {
        if (di.GetFileSystemInfos().Length == 0)
            return;
        Console.WriteLine(di.FullName + i);
        Thread.Sleep(50 * i);
    }
}

Che cos'è stackoverflow.com/questions/12415105/… "Quando si chiama Directory.Delete e un file viene aperto in questo modo, Directory.Delete riesce a eliminare tutti i file ma quando Directory.Delete chiama RemoveDirectory una" directory non è vuota " viene generata un'eccezione perché esiste un file contrassegnato per l'eliminazione ma non effettivamente eliminato. "
Kiquenet,

@Kiquenet: sembra che abbiamo riscontrato un problema in Windows. Windows avrebbe potuto consultare l'elenco dei file contrassegnati per l'eliminazione e se tutti i file nella directory sono contrassegnati per l'eliminazione, non dire che la directory non è vuota. Comunque il mio WaitForDirectoryToBecomeEmpty () è una soluzione alternativa.
farfareast,

2

Questa versione non utilizza chiamate ricorsive e risolve il problema di sola lettura.

public static void EmptyDirectory(string directory)
{
    // First delete all the files, making sure they are not readonly
    var stackA = new Stack<DirectoryInfo>();
    stackA.Push(new DirectoryInfo(directory));

    var stackB = new Stack<DirectoryInfo>();
    while (stackA.Any())
    {
        var dir = stackA.Pop();
        foreach (var file in dir.GetFiles())
        {
            file.IsReadOnly = false;
            file.Delete();
        }
        foreach (var subDir in dir.GetDirectories())
        {
            stackA.Push(subDir);
            stackB.Push(subDir);
        }
    }

    // Then delete the sub directories depth first
    while (stackB.Any())
    {
        stackB.Pop().Delete();
    }
}

1

utilizzare il metodo GetDirectories di DirectoryInfo.

foreach (DirectoryInfo subDir in new DirectoryInfo(targetDir).GetDirectories())
                    subDir.Delete(true);

1

L'esempio seguente mostra come farlo. Crea prima alcune directory e un file, quindi le rimuove tramite Directory.Delete(topPath, true);:

    static void Main(string[] args)
    {
        string topPath = @"C:\NewDirectory";
        string subPath = @"C:\NewDirectory\NewSubDirectory";

        try
        {
            Directory.CreateDirectory(subPath);

            using (StreamWriter writer = File.CreateText(subPath + @"\example.txt"))
            {
                writer.WriteLine("content added");
            }

            Directory.Delete(topPath, true);

            bool directoryExists = Directory.Exists(topPath);

            Console.WriteLine("top-level directory exists: " + directoryExists);
        }
        catch (Exception e)
        {
            Console.WriteLine("The process failed: {0}", e.Message);
        }
    }

È preso da https://msdn.microsoft.com/en-us/library/fxeahc5f(v=vs.110).aspx .


1

Non è il modo migliore per affrontare il problema sopra. Ma è alternativo ...

while (Directory.GetDirectories(dirpath).Length > 0)
 {
       //Delete all files in directory
       while (Directory.GetFiles(Directory.GetDirectories(dirpath)[0]).Length > 0)
       {
            File.Delete(Directory.GetFiles(dirpath)[0]);
       }
       Directory.Delete(Directory.GetDirectories(dirpath)[0]);
 }

0
DirectoryInfo Folder = new DirectoryInfo(Server.MapPath(path)); 
if (Folder .Exists)
{
    foreach (FileInfo fl in Folder .GetFiles())
    {
        fl.Delete();
    }

    Folder .Delete();
}

Potresti essere più specifico e spiegare come e perché dovrebbe funzionare?
Deep Frozen,

3
Le risposte con solo codice non sono adatte. Dovresti spiegare come e perché dovrebbe funzionare / risolvere il problema.
rdurand,

0

questo mostrerà come eliminiamo la cartella e per controllarla usiamo la casella di testo

using System.IO;
namespace delete_the_folder
{
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void Deletebt_Click(object sender, EventArgs e)
    {
        //the  first you should write the folder place
        if (Pathfolder.Text=="")
        {
            MessageBox.Show("ples write the path of the folder");
            Pathfolder.Select();
            //return;
        }

        FileAttributes attr = File.GetAttributes(@Pathfolder.Text);

        if (attr.HasFlag(FileAttributes.Directory))
            MessageBox.Show("Its a directory");
        else
            MessageBox.Show("Its a file");

        string path = Pathfolder.Text;
        FileInfo myfileinf = new FileInfo(path);
        myfileinf.Delete();

    }


}

}

0
using System.IO;

string[] filePaths = Directory.GetFiles(@"c:\MyDir\");

foreach (string filePath in filePaths)

File.Delete(filePath);

0

Chiama dalla rete principale

static void Main(string[] args)
{ 
   string Filepathe =<Your path>
   DeleteDirectory(System.IO.Directory.GetParent(Filepathe).FullName);              
}

Aggiungi questo metodo

public static void DeleteDirectory(string path)
{
    if (Directory.Exists(path))
    {
        //Delete all files from the Directory
        foreach (string file in Directory.GetFiles(path))
        {
            File.Delete(file);
        }
        //Delete all child Directories
        foreach (string directory in Directory.GetDirectories(path))
        {
             DeleteDirectory(directory);
        }
        //Delete a Directory
        Directory.Delete(path);
    }
 }

0
 foreach (string file in System.IO.Directory.GetFiles(path))
 {
    System.IO.File.Delete(file);
 }

 foreach (string subDirectory in System.IO.Directory.GetDirectories(path))
 {
     System.IO.Directory.Delete(subDirectory,true); 
 } 

0

Per eliminare la cartella, si tratta di un codice che utilizza la casella di testo e un pulsante using System.IO;:

private void Deletebt_Click(object sender, EventArgs e)
{
    System.IO.DirectoryInfo myDirInfo = new DirectoryInfo(@"" + delete.Text);

    foreach (FileInfo file in myDirInfo.GetFiles())
    {
       file.Delete();
    }
    foreach (DirectoryInfo dir in myDirInfo.GetDirectories())
    {
       dir.Delete(true);
    }
}

-2
private void ClearDirectory(string path)
{
    if (Directory.Exists(path))//if folder exists
    {
        Directory.Delete(path, true);//recursive delete (all subdirs, files)
    }
    Directory.CreateDirectory(path);//creates empty directory
}

2
Vedi sotto ... "eliminare e ricreare" non equivale a conservare, tutte le personalizzazioni ACL andranno perse.
Marc L.,

Ho provato qualcosa di molto simile a questo dal momento che non mi importava e personalizzazioni ACL e ho riscontrato problemi con la cartella non creata dopoDirectory.CreateDirectory
JG in SD

-3

L'unica cosa da fare è impostare optional recursive parametera True.

Directory.Delete("C:\MyDummyDirectory", True)

Grazie a .NET. :)


3
Questo elimina anche la directory stessa.
rajat,

-4
IO.Directory.Delete(HttpContext.Current.Server.MapPath(path), True)

Non hai bisogno di altro


2
Sbagliato ... questo eliminerà anche la directory principale.
L-Four,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.