Comment supprimer tous les fichiers et dossiers d'un répertoire?

663

En utilisant C #, comment puis-je supprimer tous les fichiers et dossiers d'un répertoire, tout en conservant le répertoire racine?

JL.
la source
11
Ce qui serait bien si DirectoryInfo avait une méthode comme .Clean ();
JL.
6
ou .DeleteFolders et DeleteFiles.
JL.
18
Vous devez savoir que vos suppressions peuvent très facilement lever une exception si un fichier est verrouillé (ou si vous n'avez pas de droits). Voir FileInfo.Delete pour une liste des exceptions.
Shane Courtrille

Réponses:

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

Si votre répertoire peut contenir de nombreux fichiers, il EnumerateFiles()est plus efficace que cela GetFiles(), car lorsque vous l'utilisez, EnumerateFiles()vous pouvez commencer à l'énumérer avant que la collection entière ne soit retournée, par opposition à l' GetFiles()endroit où vous devez charger la collection entière en mémoire avant de commencer à l'énumérer. Voir cette citation ici :

Par conséquent, lorsque vous travaillez avec de nombreux fichiers et répertoires, EnumerateFiles () peut être plus efficace.

Il en va de même pour EnumerateDirectories()et GetDirectories(). Le code serait donc:

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

Aux fins de cette question, il n'y a vraiment aucune raison d'utiliser GetFiles()et GetDirectories().

gsharp
la source
6
Qu'est-ce qui concerne stackoverflow.com/questions/12415105/… "Lorsque vous appelez Directory.Delete et qu'un fichier est ouvert de cette manière, Directory.Delete réussit à supprimer tous les fichiers mais lorsque Directory.Delete appelle RemoveDirectory un" répertoire n'est pas vide " une exception est levée car il existe un fichier marqué pour suppression mais pas réellement supprimé. "
Kiquenet
74
DirectoryInfo est lent car il rassemble beaucoup plus de données. BTW: Directory.Delete(path, true)s'occupera de tout :)
AcidJunkie
57
@AcidJunkie, Cela supprimera également le répertoire en question, tandis que l'OP demande spécifiquement que le répertoire racine soit conservé.
Marc L.
5
Notez que cela ne fonctionnera pas si l'un des fichiers est en lecture seule. Vous devez supprimer l'indicateur de lecture seule avant d'appeler file.Delete().
Ben
8
Cela semble ne pas fonctionner si les sous-répertoires contiennent des fichiers.
cdiggins
174

Oui, c'est la bonne façon de procéder. Si vous cherchez à vous donner une fonction "Clean" (ou, comme je préfère l'appeler, "Empty"), vous pouvez créer une méthode d'extension.

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

Cela vous permettra ensuite de faire quelque chose comme ..

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

directory.Empty();
Adam Robinson
la source
4
La dernière ligne doit être subDirectory.Delete (true) au lieu de directory.Delete (true). Je viens de couper et coller le code et il a supprimé le répertoire principal lui-même. Merci pour le code c'est super!
Aximili
26
notez qu'il Emptyexiste déjà en C #, pour string. Si je voyais quelque chose d'autre nommé Emptyje serais surpris s'il modifiait l'objet (ou le système de fichiers) au lieu de me donner un boolqui dit s'il est vide ou non. Pour cette raison, j'irais avec le nom Clean.
Par défaut
5
@Default: Je ne pense pas que le fait qu'un type ait déjà une propriété devrait avoir une incidence sur la question de savoir si un autre type (complètement indépendant) devrait l'avoir; et la convention pour les propriétés et les fonctions qui indiquent l'état des mots qui peuvent également être des verbes est de les préfixer Is(c'est-à-dire IsEmptyplutôt que Empty).
Adam Robinson
3
@AdamRobinson Je voulais juste en prendre note. Pour moi , ce que Microsoft a dans son code a une certaine incidence. Mais c'est à tout le monde d'interpréter :)
Par défaut
4
@simonhaines: Le but de la question était de vider le répertoire (c'est-à-dire de supprimer tout ce qu'il contient ), pas de supprimer le répertoire lui-même.
Adam Robinson
77

Le code suivant effacera le dossier récursivement:

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();
    }
}
hiteshbiblog
la source
A fonctionné pour moi, tandis que Directory.Delete (chemin, vrai); jeté en se plaignant que le dossier n'était pas vide
Jack Griffin
40
 new System.IO.DirectoryInfo(@"C:\Temp").Delete(true);

 //Or

 System.IO.Directory.Delete(@"C:\Temp", true);
Thulasiram
la source
1
La deuxième option, Directory.Delete (String, Boolean) a fonctionné pour moi.
Stephen MacDougall
15
Cela supprime le répertoire racine, où l'OP a spécifiquement demandé qu'il soit conservé.
Marc L.
2
Deletejettera si le répertoire n'existe pas, il serait donc plus sûr de faire une Directory.Existsvérification en premier.
James
1
@James Directory.Existsn'est pas suffisant; après la vérification, un autre thread peut avoir renommé ou supprimé le répertoire. C'est plus sûr try-catch.
andre_ss6
2
@Marv Attention à simplement ajouter un Directory.Createcar le récursif Directory.Deleten'est malheureusement pas garanti d'être synchrone ..
Andrew Hanlon
38

Nous pouvons également montrer notre amour pour 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));

Notez que ma solution ici n'est pas performante, car j'utilise Get*().ToList().ForEach(...)ce qui génère le même IEnumerabledeux fois. J'utilise une méthode d'extension pour éviter ce problème:

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

Voici la méthode d'extension:

/// <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);
        }
    }
}
rasx
la source
1
Et si vous essayez également de supprimer des sous-répertoires, cela foreach (var dir in info.GetDirectories("*", SearchOption.AllDirectories).OrderByDescending(dir => dir.FullName.Length)) dir.Delete();pourrait être utile.
Warty
1
Si vous aimez les performances, pensez à utiliser directory.EnumerateFiles()et directory.EnumerateDirectories()au lieu des directory.Get*()méthodes.
Tinister
1
Drôle, ma propre IEnumerable<T>.ForEach()extension a un commentaire XML résumé, "Violation! Violation! Impur!".
Marc L.
Hé quelle est la 2ème raison? Le 3ème? Etc.?
Bill Roberts
lol @RASX - il vous parle: "Si vous n'êtes pas d'accord avec ces objections philosophiques et que vous trouvez une valeur pratique dans ce modèle, allez-y et écrivez vous-même cette ligne triviale."
Bill Roberts
37

La manière la plus simple:

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

N'oubliez pas que cela peut effacer certaines autorisations sur le dossier.

Igor Mukhachev
la source
9
sachez que cela supprimera toutes les autorisations spéciales du chemin d'accès
Matthew Lock
6
Vous devez ajouter un délai d'attente entre ces deux actions. essayez d'exécuter ce code et vous obtiendrez Exception: 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
    }
}

Si vous savez qu'il n'y a pas de sous-dossiers, quelque chose comme ça peut être le plus simple:

    Directory.GetFiles(folderName).ForEach(File.Delete)
zumalifeguard
la source
J'ai utilisé cette fonction pour effacer le dossier temporaire du système. J'ai juste ajouté try-catch autour de Delete () et IsReadOnly pour ignorer toutes les exceptions, et cela a fonctionné.
humbads
@humbads, pouvez-vous mettre à jour cette réponse, ou mettre le code ici, et je mettrai à jour vos modifications?
zumalifeguard
13
System.IO.Directory.Delete(installPath, true);
System.IO.Directory.CreateDirectory(installPath);
MacGyver
la source
3
comme ci-dessus: sachez que cela supprimera toutes les autorisations spéciales du chemin.
hB0
8

Toutes les méthodes que j'ai essayées ont échoué à un moment donné avec des erreurs System.IO. La méthode suivante fonctionne à coup sûr, même si le dossier est vide ou non, en lecture seule ou non, etc.

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); 
Alexandru Dicu
la source
1
Je préfère toujours rd / s / q + mkdir pour vider les répertoires.
Dawid Ohia
7
Ce n'est pas une solution multiplateforme. Les systèmes de type Unix n'ont clairement pas cmd.exe, ils n'exécutent même pas de fichiers .exe. C # n'est pas seulement Windows, il y a aussi Mono, qui est multi-plateforme.
Nom d'affichage
1
@SargeBorsch, il n'y avait aucune exigence multiplateforme dans la question et étant C #, il est très probable que la solution sera utilisée pour Windows. Il semble que ce soit la seule réponse qui n'utilise pas les fonctions .NET, c'est donc très utile comme alternative.
Alex Pandrea
7

Voici l'outil avec lequel j'ai terminé après avoir lu tous les articles. Cela fait

  • Supprime tout ce qui peut être supprimé
  • Renvoie false si certains fichiers restent dans le dossier

Ça parle de

  • Fichiers en lecture seule
  • Délai de suppression
  • Fichiers verrouillés

Il n'utilise pas Directory.Delete car le processus est abandonné à l'exception.

    /// <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;
    }
Eric Bole-Feysot
la source
6

Le code suivant nettoiera le répertoire, mais y laissera le répertoire racine (récursif).

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);
hofi
la source
6

j'ai utilisé

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

pour supprimer la vieille photo et je n'ai besoin d'aucun objet dans ce dossier

Mohammad Farahani
la source
1
Pas sûr que vous ayez besoin du .ToList ()
Ben Power
5

L'utilisation de méthodes statiques avec File and Directory au lieu de FileInfo et DirectoryInfo fonctionnera plus rapidement. (voir la réponse acceptée à Quelle est la différence entre File et FileInfo en C #? ). Réponse affichée comme méthode d'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);
    }
}
Kriil
la source
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();
    }
}
Mong Zhu
la source
3
string directoryPath = "C:\Temp";
Directory.GetFiles(directoryPath).ToList().ForEach(File.Delete);
Directory.GetDirectories(directoryPath).ToList().ForEach(Directory.Delete);
AVH
la source
Une exception de type «System.IO.IOException» s'est produite dans mscorlib.dll mais n'a pas été gérée dans le code utilisateur Informations supplémentaires: le répertoire n'est pas vide.
kipusoep
3

Dans Windows 7, si vous venez de le créer manuellement avec l'Explorateur Windows, la structure du répertoire est similaire à celle-ci:

C:
  \AAA
    \BBB
      \CCC
        \DDD

Et en exécutant le code suggéré dans la question d'origine pour nettoyer le répertoire C: \ AAA, la ligne di.Delete(true)échoue toujours avec IOException "Le répertoire n'est pas vide" lorsque vous essayez de supprimer BBB. C'est probablement à cause d'une sorte de retard / mise en cache dans l'Explorateur Windows.

Le code suivant fonctionne de manière fiable pour moi:

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);
    }
}
farfareast
la source
Qu'est-ce qui concerne stackoverflow.com/questions/12415105/… "Lorsque vous appelez Directory.Delete et qu'un fichier est ouvert de cette manière, Directory.Delete réussit à supprimer tous les fichiers mais lorsque Directory.Delete appelle RemoveDirectory un" répertoire n'est pas vide " une exception est levée car il existe un fichier marqué pour suppression mais pas réellement supprimé. "
Kiquenet
@Kiquenet: On dirait que nous avons trouvé un problème dans Windows. Windows aurait pu consulter la liste des fichiers marqués pour suppression et si tous les fichiers du répertoire sont marqués pour suppression, ne dites pas que le répertoire n'est pas vide. Quoi qu'il en soit, mon WaitForDirectoryToBecomeEmpty () est une solution de contournement.
farfareast
2

Cette version n'utilise pas d'appels récursifs et résout le problème en lecture seule.

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();
    }
}
Jeppe Andreasen
la source
1

utilisez la méthode GetDirectories de DirectoryInfo.

foreach (DirectoryInfo subDir in new DirectoryInfo(targetDir).GetDirectories())
                    subDir.Delete(true);
Mr_Hmp
la source
1

L'exemple suivant montre comment procéder. Il crée d'abord des répertoires et un fichier, puis les supprime via 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);
        }
    }

Il est extrait de https://msdn.microsoft.com/en-us/library/fxeahc5f(v=vs.110).aspx .

Salma Tofaily
la source
1

Ce n'est pas la meilleure façon de traiter le problème ci-dessus. Mais c'est une alternative ...

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]);
 }
dsmyrnaios
la source
0
DirectoryInfo Folder = new DirectoryInfo(Server.MapPath(path)); 
if (Folder .Exists)
{
    foreach (FileInfo fl in Folder .GetFiles())
    {
        fl.Delete();
    }

    Folder .Delete();
}
Ashok Luhach
la source
Pourriez-vous être plus précis et expliquer comment et pourquoi cela devrait fonctionner?
Deep Frozen
3
Les réponses avec un seul code ne conviennent pas. Vous devez expliquer comment et pourquoi cela devrait fonctionner / résoudre le problème.
rdurand
0

cela montrera comment nous supprimons le dossier et le vérifions, nous utilisons la zone de texte

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

    }


}

}
Abdelrhman Khalil
la source
0
using System.IO;

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

foreach (string filePath in filePaths)

File.Delete(filePath);
SynsMasTer
la source
0

Appel du principal

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

Ajoutez cette méthode

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);
    }
 }
sansalk
la source
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); 
 } 
Manish Y
la source
0

Pour supprimer le dossier, voici le code à l'aide de la zone de texte et d'un bouton 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);
    }
}
Abdelrhman Khalil
la source
-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
}
dadziu
la source
2
Voir ci-dessous ... "supprimer et recréer" n'est pas la même chose que conserver, toutes les personnalisations ACL seront perdues.
Marc L.
J'ai essayé quelque chose de très similaire à cela depuis que je ne me souciais pas des personnalisations ACL et que je rencontrais des problèmes avec le dossier qui n'était pas créé aprèsDirectory.CreateDirectory
JG dans SD
-3

La seule chose que vous devez faire est de mettre optional recursive parameterà True.

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

Merci à .NET. :)

LysanderM
la source
3
Cela supprime également le répertoire lui-même.
rajat
-4
IO.Directory.Delete(HttpContext.Current.Server.MapPath(path), True)

Tu n'as pas besoin de plus que ça

Mustafa Odeh
la source
2
Incorrect ... cela supprimera également le répertoire racine.
L-Four