Como excluir todos os arquivos e pastas em um diretório?


663

Usando o C #, como posso excluir todos os arquivos e pastas de um diretório, mas ainda assim manter o diretório raiz?


11
O que seria bom se DirectoryInfo tivesse um método como .Clean ();
JL.

6
ou .DeleteFolders e DeleteFiles.
JL.

18
Você deseja estar ciente de que suas exclusões podem facilmente lançar uma exceção se um arquivo estiver bloqueado (ou se você não tiver direitos). Consulte o FileInfo.Delete para obter uma lista das exceções.
Shane Courtrille

Respostas:


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 seu diretório tiver muitos arquivos, EnumerateFiles()é mais eficiente que GetFiles(), porque, quando você o usa, EnumerateFiles()pode começar a enumerá-lo antes que a coleção inteira seja retornada, ao contrário de GetFiles()onde você precisa carregar a coleção inteira na memória antes de começar a enumerá-la. Veja esta citação aqui :

Portanto, quando você estiver trabalhando com muitos arquivos e diretórios, EnumerateFiles () pode ser mais eficiente.

O mesmo se aplica a EnumerateDirectories()e GetDirectories(). Portanto, o código seria:

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

Para os fins desta pergunta, não há realmente nenhuma razão para usar GetFiles()e GetDirectories().


6
O que há com stackoverflow.com/questions/12415105/… "Quando você chama Directory.Delete e um arquivo é aberto dessa maneira, o Directory.Delete consegue excluir todos os arquivos, mas quando o Directory.Delete chama RemoveDirectory como um diretório" não está vazio " a exceção é lançada porque existe um arquivo marcado para exclusão, mas na verdade não foi excluído ".
Kiquenet

74
O DirectoryInfo é lento, pois reúne muito mais dados. BTW: Directory.Delete(path, true)vai cuidar de tudo :)
AcidJunkie

57
@AcidJunkie, Isso também removerá o diretório em questão, enquanto o OP solicita especificamente que o diretório raiz seja mantido.
Marc L.

5
Observe que isso não funcionará se algum dos arquivos for somente leitura. Você precisa remover o sinalizador somente leitura antes de ligar file.Delete().
Ben

8
Isso parece não funcionar se os subdiretórios contiverem arquivos.
Cdggins

174

Sim, essa é a maneira correta de fazer isso. Se você deseja dar a si mesmo uma função "Limpa" (ou, como eu preferiria chamar de "Vazia"), você pode criar um método de extensão.

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

Isso permitirá que você faça algo como ..

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

directory.Empty();

4
A última linha deve ser subDirectory.Delete (true) em vez de directory.Delete (true). Eu apenas recortei e colei o código e ele excluiu o próprio diretório principal. Obrigado pelo código, é ótimo!
Aximili

26
observe que já Emptyexiste em C # para string. Se eu visse outra coisa chamada Empty, ficaria surpreso se ele modificasse o objeto (ou sistema de arquivos) em vez de fornecer um boolque diz se está vazio ou não. Por causa disso, eu iria com o nome Clean.
Padrão

5
@ Padrão: Eu não acho que o fato de um tipo ter uma propriedade já deva ter alguma influência sobre se outro tipo (completamente não relacionado) deveria tê-la; e a convenção para propriedades e funções que indicam estado para palavras que também podem ser verbos é prefixá-las com Is(ou seja, em IsEmptyvez de Empty).
Adam Robinson

3
@AdamRobinson Só queria tomar nota disso. Para mim , o que a Microsoft tem em seu código tem alguma influência. Mas é para todo mundo interpretar :) #
Default

4
@simonhaines: O objetivo da pergunta era esvaziar o diretório (ou seja, excluir tudo dentro dele ), não excluir o diretório em si.
Adam Robinson

77

O código a seguir limpará a pasta recursivamente:

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

Trabalhou para mim, enquanto Directory.Delete (caminho, verdadeiro); jogado reclamando que a pasta não estava vazia
Jack Griffin

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

 //Or

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

1
A segunda opção, Directory.Delete (String, Boolean), funcionou para mim.
Stephen MacDougall

15
Isso exclui o diretório raiz, onde o OP solicitou especificamente que ele fosse retido.
Marc L.

2
Deleteserá lançado se o diretório não existir, portanto, seria mais seguro fazer uma Directory.Existsverificação primeiro.
James

1
@ James Directory.Existsnão é suficiente; após a verificação, outro segmento pode ter renomeado ou removido o diretório. É mais seguro try-catch.
precisa saber é o seguinte

2
@Marv Cuidado com simplesmente adicionando um Directory.Createporque o recursiva Directory.Deleteinfelizmente não é garantido para ser síncrono ..
Andrew Hanlon

38

Também podemos mostrar amor pelo 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));

Observe que minha solução aqui não tem desempenho, porque estou usando o Get*().ToList().ForEach(...)que gera o mesmo IEnumerableduas vezes. Eu uso um método de extensão para evitar esse 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 é o método de extensão:

/// <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 você estiver tentando excluir subdiretórios também, foreach (var dir in info.GetDirectories("*", SearchOption.AllDirectories).OrderByDescending(dir => dir.FullName.Length)) dir.Delete();pode ser útil.
Warty

1
Se você gosta de desempenho, considere usar directory.EnumerateFiles()e directory.EnumerateDirectories()não os directory.Get*()métodos.
Tinister

1
Engraçado, minha própria IEnumerable<T>.ForEach()extensão possui um comentário XML resumido, "Violação! Violação! Imundo!".
27468 Marc

Ei, qual é o segundo motivo? O terceiro? Etc.?
Bill Roberts

lol @RASX - ele está falando com você: "Se você não concorda com essas objeções filosóficas e encontra valor prático nesse padrão, vá em frente e escreva você mesmo essa frase trivial".
Bill Roberts

37

A maneira mais simples:

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

Esteja ciente de que isso pode acabar com algumas permissões na pasta.


9
esteja ciente de que isso removerá todas as permissões especiais que o caminho tinha #
Matthew Lock

6
Você precisa adicionar tempo limite entre essas duas ações. tente executar esse código e você receberá a exceção: while (true) {Directory.Delete (@ "C: \ Myfolder", true); Directory.CreateDirectory (@ "C: \ Myfolder"); }
RcMan 22/03

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 você sabe que não há subpastas, algo como isto pode ser o mais fácil:

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

Eu usei essa função para limpar a pasta temp do sistema. Acabei de adicionar try-catch em torno de Delete () e IsReadOnly para ignorar todas as exceções, e funcionou.
humbads

@umbumbs, você pode atualizar esta resposta ou colocar o código aqui, e eu atualizarei com suas alterações?
zumalifeguard 8/19

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

3
O mesmo que acima: lembre-se de que isso removerá todas as permissões especiais que o caminho possui.
hB0 31/05

8

Todo método que eu tentei, eles falharam em algum momento com os erros do System.IO. O método a seguir funciona com certeza, mesmo se a pasta estiver vazia ou não, somente leitura ou não, 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); 

1
Eu sempre prefiro rd / s / q + mkdir quando se trata de esvaziar diretórios.
Dawid Ohia

7
Esta não é uma solução multiplataforma. Os sistemas tipo Unix claramente não possuem o cmd.exe, eles nem executam arquivos .exe. O C # não é apenas Windows, também há o Mono, que é multiplataforma.
Nome para exibição

1
@SargeBorsch, não havia requisitos de plataforma cruzada na pergunta e, como C #, é mais provável que a solução seja usada para Windows. Parece ser a única resposta que não usa funções .NET, por isso é bastante valiosa como alternativa.
precisa saber é o seguinte

7

Aqui está a ferramenta com a qual terminei depois de ler todas as postagens. Faz

  • Exclui tudo o que pode ser excluído
  • Retorna false se alguns arquivos permanecerem na pasta

Lida com

  • Arquivos somente leitura
  • Atraso na exclusão
  • Arquivos bloqueados

Ele não usa Directory.Delete porque o processo é interrompido por exceção.

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

O código a seguir limpará o diretório, mas deixará o diretório raiz (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);

6

eu usei

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

para excluir imagens antigas e não preciso de nenhum objeto nesta pasta


1
Não tenho certeza de que você precisa do .ToList ()
Ben Power

5

Usar apenas métodos estáticos com File and Directory em vez de FileInfo e DirectoryInfo terá um desempenho mais rápido. (consulte a resposta aceita em Qual é a diferença entre File e FileInfo em C #? ). Resposta mostrada como método utilitário.

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

Ocorreu uma exceção do tipo 'System.IO.IOException' no mscorlib.dll, mas não foi tratada no código do usuário Informações adicionais: O diretório não está vazio.
Kipusoep

3

No Windows 7, se você acabou de criar manualmente com o Windows Explorer, a estrutura de diretórios é semelhante a esta:

C:
  \AAA
    \BBB
      \CCC
        \DDD

E executando o código sugerido na pergunta original para limpar o diretório C: \ AAA, a linha di.Delete(true) sempre falha com IOException "O diretório não está vazio" ao tentar excluir o BBB. Provavelmente é devido a algum tipo de atraso / cache no Windows Explorer.

O código a seguir funciona de maneira confiável para mim:

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

O que há com stackoverflow.com/questions/12415105/… "Quando você chama Directory.Delete e um arquivo é aberto dessa maneira, o Directory.Delete consegue excluir todos os arquivos, mas quando o Directory.Delete chama RemoveDirectory como um diretório" não está vazio " a exceção é lançada porque existe um arquivo marcado para exclusão, mas na verdade não foi excluído ".
19713 Kiquenet

@Kiquenet: Parece que encontramos um problema no Windows. O Windows poderia ter consultado a lista de arquivos marcados para exclusão e se todos os arquivos no diretório estiverem marcados para exclusão, não diga que o diretório não está vazio. De qualquer forma, meu WaitForDirectoryToBecomeEmpty () é uma solução alternativa.
farfareast

2

Esta versão não usa chamadas recursivas e resolve o problema somente leitura.

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

use o método GetDirectories do DirectoryInfo.

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

1

O exemplo a seguir mostra como você pode fazer isso. Primeiro, ele cria alguns diretórios e um arquivo e os remove 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);
        }
    }

É obtido em https://msdn.microsoft.com/en-us/library/fxeahc5f(v=vs.110).aspx .


1

Não é a melhor maneira de lidar com o problema acima. Mas é uma 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]);
 }

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

    Folder .Delete();
}

Você poderia ser mais específico e explicar como e por que isso deveria funcionar?
congelados

3
Respostas com apenas código não são adequadas. Você deve explicar como e por que ele deve funcionar / resolver o problema.
Rdurand

0

isso mostrará como excluímos a pasta e verificamos se usamos a caixa 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();

    }


}

}

0
using System.IO;

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

foreach (string filePath in filePaths)

File.Delete(filePath);

0

Chamada do principal

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

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

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

Para excluir a pasta, este é o código usando a caixa de texto e um botão 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
Veja abaixo ... "excluir e recriar" não é o mesmo que manter, todas as personalizações da ACL serão perdidas.
Marc L.

Eu tentei algo muito semelhante a esta desde que eu não me importava com e ACL personalizações e correu para problemas com a pasta não foi criada depoisDirectory.CreateDirectory
JG em SD

-3

A única coisa que você deve fazer é definir optional recursive parametera True.

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

Graças ao .NET. :)


3
Isso também exclui o próprio diretório.
rajat

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

Você não precisa de mais do que isso


2
Errado ... isso também excluirá o diretório raiz.
L-Four
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.