¿Cómo eliminar todos los archivos y carpetas en un directorio?

663

Con C #, ¿cómo puedo eliminar todos los archivos y carpetas de un directorio, pero aún así mantener el directorio raíz?

JL
fuente
11
Lo que sería bueno si DirectoryInfo tuviera un método como .Clean ();
JL.
66
o .DeleteFolders, y DeleteFiles métodos.
JL.
18
Desea saber que sus eliminaciones podrían generar fácilmente una excepción si un archivo está bloqueado (o si no tiene derechos). Consulte FileInfo.Delete para obtener una lista de las excepciones.
Shane Courtrille

Respuestas:

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 su directorio puede tener muchos archivos, EnumerateFiles()es más eficiente que GetFiles(), porque cuando lo usa EnumerateFiles(), puede comenzar a enumerarlo antes de que se devuelva toda la colección, en lugar de GetFiles()donde necesita cargar toda la colección en la memoria antes de comenzar a enumerarla. Vea esta cita aquí :

Por lo tanto, cuando trabaja con muchos archivos y directorios, EnumerateFiles () puede ser más eficiente.

Lo mismo se aplica a EnumerateDirectories()y GetDirectories(). Entonces el código sería:

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

Para el propósito de esta pregunta, realmente no hay razón para usar GetFiles()y GetDirectories().

gsharp
fuente
66
De qué se trata stackoverflow.com/questions/12415105/… "Cuando llama a Directory.Delete y un archivo está abierto de esa manera, Directory.Delete logra eliminar todos los archivos pero cuando Directory.Delete llama a RemoveDirectory un" directorio no está vacío " se genera una excepción porque hay un archivo marcado para su eliminación pero que en realidad no se ha eliminado ".
Kiquenet
74
DirectoryInfo es lento ya que esto recopila muchos más datos. Por cierto: Directory.Delete(path, true)se encargará de todo :)
AcidJunkie
57
@AcidJunkie, eso también eliminará el directorio en cuestión, mientras que el OP solicita específicamente que se mantenga el directorio raíz.
Marc L.
55
Tenga en cuenta que esto no funcionará si alguno de los archivos es de solo lectura. Debe eliminar el indicador de solo lectura antes de llamar file.Delete().
Ben
8
Esto parece no funcionar si los subdirectorios contienen archivos.
cdiggins
174

Sí, esa es la forma correcta de hacerlo. Si está buscando darse una función "Limpio" (o, como prefiero llamarlo, función "Vacío"), puede crear un método de extensión.

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

Esto te permitirá hacer algo como ...

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

directory.Empty();
Adam Robinson
fuente
44
La última línea debe ser subDirectory.Delete (true) en lugar de directory.Delete (true). Acabo de cortar y pegar el código y eliminó el directorio principal en sí. Gracias por el código, ¡es genial!
Aximili
26
tenga Emptyen cuenta que ya existe en C #, para string. Si viera algo más llamado, Emptyme sorprendería si modificara el objeto (o el sistema de archivos) en lugar de darme un boolmensaje que diga si está vacío o no. Por eso, iría con el nombre Clean.
Predeterminado
55
@Default: no creo que el hecho de que un tipo tenga una propiedad ya debería influir en si otro tipo (completamente no relacionado) debería tenerla; y la convención para propiedades y funciones que indican el estado de palabras que también pueden ser verbos es prefijarlas con Is(es decir, en IsEmptylugar de Empty).
Adam Robinson
3
@AdamRobinson Solo quería tomar nota de ello. Para , lo que Microsoft tiene en su código tiene cierta relación. Pero es para que todos interpreten :)
Predeterminado
44
@simonhaines: El punto de la cuestión fue a vaciar el directorio (es decir, borrar todo dentro de ella ), no eliminar el directorio en sí.
Adam Robinson
77

El siguiente código borrará la carpeta de forma recursiva:

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
fuente
Me funcionó, mientras que Directory.Delete (ruta, verdadero); arrojado quejándose de que la carpeta no estaba vacía
Jack Griffin
40
 new System.IO.DirectoryInfo(@"C:\Temp").Delete(true);

 //Or

 System.IO.Directory.Delete(@"C:\Temp", true);
Tulasiram
fuente
1
La segunda opción, Directory.Delete (String, Boolean) funcionó para mí.
Stephen MacDougall
15
Esto elimina el directorio raíz, donde el OP solicitó específicamente que se retenga.
Marc L.
2
Deletelanzará si el directorio no existe, por lo que sería más seguro hacer una Directory.Existsverificación primero.
James
1
@James Directory.Existsno es suficiente; después de la verificación, otro hilo puede haber renombrado o eliminado el directorio. Es más seguro try-catch.
andre_ss6
2
@Marv Cuidado con simplemente agregar un Directory.Createporque el recursivo Directory.Deletedesafortunadamente no se garantiza que sea sincrónico ..
Andrew Hanlon
38

También podemos mostrar amor por 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));

Tenga en cuenta que mi solución aquí no es eficaz, porque estoy usando lo Get*().ToList().ForEach(...)que genera lo mismo IEnumerabledos veces. Utilizo un método de extensión para evitar este 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));

Este es el método de extensión:

/// <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
fuente
1
Y si también está intentando eliminar subdirectorios, foreach (var dir in info.GetDirectories("*", SearchOption.AllDirectories).OrderByDescending(dir => dir.FullName.Length)) dir.Delete();podría ser útil.
Warty
1
Si le gusta el rendimiento, considere usar directory.EnumerateFiles()y en directory.EnumerateDirectories()lugar de los directory.Get*()métodos.
Tinister
1
Es curioso, mi propia IEnumerable<T>.ForEach()extensión tiene un comentario XML de resumen, "¡Violación! ¡Violación! ¡Inmundo!".
Marc L.
¿Cuál es la segunda razón? ¿La tercera? Etc.?
Bill Roberts el
jajaja @RASX - te está hablando: "Si no estás de acuerdo con estas objeciones filosóficas y encuentras valor práctico en este patrón, por supuesto, sigue adelante y escribe este trivial trazo tuyo".
Bill Roberts
37

La forma más simple:

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

Tenga en cuenta que esto puede eliminar algunos permisos en la carpeta.

Igor Mukhachev
fuente
99
tenga en cuenta que esto eliminará los permisos especiales que tenía el camino
Matthew Lock
66
Necesita agregar tiempo de espera entre esas dos acciones. intente ejecutar este código y obtendrá la excepción: 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 sabe que no hay subcarpetas, algo como esto puede ser lo más fácil:

    Directory.GetFiles(folderName).ForEach(File.Delete)
zumalifeguard
fuente
Utilicé esta función para borrar la carpeta temporal del sistema. Acabo de agregar try-catch alrededor de Delete () e IsReadOnly para ignorar todas las excepciones, y funcionó.
humbads
@humbads, ¿puedes actualizar esta respuesta o poner el código aquí, y actualizaré con tus cambios?
zumalifeguard
13
System.IO.Directory.Delete(installPath, true);
System.IO.Directory.CreateDirectory(installPath);
MacGyver
fuente
3
igual que el anterior: tenga en cuenta que esto eliminará los permisos especiales que tenía la ruta.
hB0
8

Todos los métodos que probé fallaron en algún momento con los errores System.IO. El siguiente método funciona con seguridad, incluso si la carpeta está vacía o no, solo lectura o no, 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
fuente
1
Siempre prefiero rd / s / q + mkdir cuando se trata de vaciar directorios.
Dawid Ohia
77
Esta no es una solución multiplataforma. Los sistemas tipo Unix claramente no tienen cmd.exe, ni siquiera ejecutan archivos .exe. C # no es solo Windows, también está Mono, que es multiplataforma.
Nombre para mostrar
1
@SargeBorsch no hubo requisitos de plataforma cruzada en la pregunta y, siendo C #, lo más probable es que la solución se use para Windows. Parece ser la única respuesta que no utiliza funciones .NET, por lo que es bastante valioso como alternativa.
Alex Pandrea
7

Aquí está la herramienta con la que terminé después de leer todas las publicaciones. Lo hace

  • Elimina todo lo que se puede eliminar.
  • Devuelve falso si algunos archivos permanecen en la carpeta

Se trata de

  • Archivos de solo lectura
  • Retraso de eliminación
  • Archivos bloqueados

No utiliza Directory.Delete porque el proceso se cancela con excepción.

    /// <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
fuente
6

El siguiente código limpiará el directorio, pero dejará el directorio raíz allí (recursivo).

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
fuente
6

solía

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

para eliminar la imagen anterior y no necesito ningún objeto en esta carpeta

Mohammad Farahani
fuente
1
No está seguro de lo que necesita el .ToList ()
Ben Power
5

El uso de métodos estáticos con File y Directory en lugar de FileInfo y DirectoryInfo funcionará más rápido. (vea la respuesta aceptada en ¿Cuál es la diferencia entre File y FileInfo en C #? ). La respuesta se muestra como método de utilidad.

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
fuente
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
fuente
3
string directoryPath = "C:\Temp";
Directory.GetFiles(directoryPath).ToList().ForEach(File.Delete);
Directory.GetDirectories(directoryPath).ToList().ForEach(Directory.Delete);
AVH
fuente
Se produjo una excepción del tipo 'System.IO.IOException' en mscorlib.dll pero no se manejó en el código de usuario Información adicional: El directorio no está vacío.
kipusoep
3

En Windows 7, si acaba de crearlo manualmente con el Explorador de Windows, la estructura del directorio es similar a esta:

C:
  \AAA
    \BBB
      \CCC
        \DDD

Y al ejecutar el código sugerido en la pregunta original para limpiar el directorio C: \ AAA, la línea di.Delete(true)siempre falla con IOException "El directorio no está vacío" al intentar eliminar BBB. Probablemente se deba a algún tipo de retraso / almacenamiento en caché en el Explorador de Windows.

El siguiente código funciona de manera confiable para mí:

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
fuente
De qué se trata stackoverflow.com/questions/12415105/… "Cuando llama a Directory.Delete y un archivo está abierto de esa manera, Directory.Delete logra eliminar todos los archivos pero cuando Directory.Delete llama a RemoveDirectory un" directorio no está vacío " se genera una excepción porque hay un archivo marcado para su eliminación pero que en realidad no se ha eliminado ".
Kiquenet
@ Kiquenet: Parece que encontramos un problema en Windows. Windows podría haber consultado la lista de archivos marcados para eliminación y si todos los archivos en el directorio están marcados para eliminación, no diga que el directorio no está vacío. De todos modos mi WaitForDirectoryToBecomeEmpty () es una solución alternativa.
farfareast
2

Esta versión no utiliza llamadas recursivas y resuelve el problema de solo lectura.

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
fuente
1

utilice el método GetDirectories de DirectoryInfo.

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

El siguiente ejemplo muestra cómo puedes hacer eso. Primero crea algunos directorios y un archivo y luego los elimina a través de 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);
        }
    }

Está tomado de https://msdn.microsoft.com/en-us/library/fxeahc5f(v=vs.110).aspx .

Salma Tofaily
fuente
1

No es la mejor manera de lidiar con el problema anterior. Pero es una alternativa ...

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

    Folder .Delete();
}
Ashok Luhach
fuente
¿Podría ser más específico y explicar cómo y por qué esto debería funcionar?
Deep Frozen
3
Las respuestas con solo código no son adecuadas. Debe explicar cómo y por qué debería funcionar / resolver el problema.
rdurand
0

esto mostrará cómo eliminamos la carpeta y verificamos si usamos el cuadro de texto

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
fuente
0
using System.IO;

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

foreach (string filePath in filePaths)

File.Delete(filePath);
SynsMasTer
fuente
0

Llamar desde principal

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

Agrega este método

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
fuente
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
fuente
0

Para eliminar la carpeta, este es el código usando el cuadro de texto y un botón 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
fuente
-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
fuente
2
Consulte a continuación ... "eliminar y volver a crear" no es lo mismo que conservar, se perderán todas las personalizaciones de ACL.
Marc L.
He intentado algo muy similar a esto ya que no me importaban las personalizaciones de ACL y encontré problemas con la carpeta que no se creó despuésDirectory.CreateDirectory
JG en SD
-3

Lo único que debe hacer es fijar optional recursive parametera True.

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

Gracias a .NET. :)

LysanderM
fuente
3
Esto también elimina el directorio en sí.
rajat
-4
IO.Directory.Delete(HttpContext.Current.Server.MapPath(path), True)

No necesitas más que eso

Mustafa Odeh
fuente
2
Incorrecto ... esto también eliminará el directorio raíz.
L-Four