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 =newDirectoryInfo("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().
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.
publicstaticvoidEmpty(thisSystem.IO.DirectoryInfo directory){foreach(System.IO.FileInfo file in directory.GetFiles()) file.Delete();foreach(System.IO.DirectoryInfo subDirectory in directory.GetDirectories()) subDirectory.Delete(true);}
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:
privatevoid clearFolder(stringFolderName){DirectoryInfo dir =newDirectoryInfo(FolderName);foreach(FileInfo fi in dir.GetFiles()){
fi.Delete();}foreach(DirectoryInfo di in dir.GetDirectories()){
clearFolder(di.FullName);
di.Delete();}}
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>publicstaticclassIEnumerableOfTExtensions{/// <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>publicstaticvoidForEachInEnumerable<TEnumerable>(thisIEnumerable<TEnumerable> enumerable,Action<TEnumerable> action){foreach(var item in enumerable){
action(item);}}}
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".
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
privatevoidClearFolder(stringFolderName){DirectoryInfo dir =newDirectoryInfo(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:
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?
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.
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>publicstaticboolEmptyFolder(string pathName){bool errors =false;DirectoryInfo dir =newDirectoryInfo(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;}
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);
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.
privatevoidClearFolder(stringFolderName){DirectoryInfo dir =newDirectoryInfo(FolderName);foreach(FileInfo fi in dir.GetFiles()){
fi.IsReadOnly=false;
fi.Delete();}foreach(DirectoryInfo di in dir.GetDirectories()){ClearFolder(di.FullName);
di.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:
staticvoidMain(string[] args){DirectoryInfo di =newDirectoryInfo(@"c:\aaa");CleanDirectory(di);}privatestaticvoidCleanDirectory(DirectoryInfo di){if(di ==null)return;foreach(FileSystemInfo fsEntry in di.GetFileSystemInfos()){CleanDirectory(fsEntry asDirectoryInfo);
fsEntry.Delete();}WaitForDirectoryToBecomeEmpty(di);}privatestaticvoidWaitForDirectoryToBecomeEmpty(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.
publicstaticvoidEmptyDirectory(string directory){// First delete all the files, making sure they are not readonlyvar stackA =newStack<DirectoryInfo>();
stackA.Push(newDirectoryInfo(directory));var stackB =newStack<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 firstwhile(stackB.Any()){
stackB.Pop().Delete();}}
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);:
Não é a melhor maneira de lidar com o problema acima. Mas é uma alternativa ...
while(Directory.GetDirectories(dirpath).Length>0){//Delete all files in directorywhile(Directory.GetFiles(Directory.GetDirectories(dirpath)[0]).Length>0){File.Delete(Directory.GetFiles(dirpath)[0]);}Directory.Delete(Directory.GetDirectories(dirpath)[0]);}
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
{publicpartialclassForm1:Form{publicForm1(){InitializeComponent();}privatevoidDeletebt_Click(object sender,EventArgs e){//the first you should write the folder placeif(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");elseMessageBox.Show("Its a file");string path =Pathfolder.Text;FileInfo myfileinf =newFileInfo(path);
myfileinf.Delete();}}}
publicstaticvoidDeleteDirectory(string path){if(Directory.Exists(path)){//Delete all files from the Directoryforeach(string file inDirectory.GetFiles(path)){File.Delete(file);}//Delete all child Directoriesforeach(string directory inDirectory.GetDirectories(path)){DeleteDirectory(directory);}//Delete a DirectoryDirectory.Delete(path);}}
Para excluir a pasta, este é o código usando a caixa de texto e um botão using System.IO;:
privatevoidDeletebt_Click(object sender,EventArgs e){System.IO.DirectoryInfo myDirInfo =newDirectoryInfo(@""+delete.Text);foreach(FileInfo file in myDirInfo.GetFiles()){
file.Delete();}foreach(DirectoryInfo dir in myDirInfo.GetDirectories()){
dir.Delete(true);}}
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.
Respostas:
Se seu diretório tiver muitos arquivos,
EnumerateFiles()
é mais eficiente queGetFiles()
, porque, quando você o usa,EnumerateFiles()
pode começar a enumerá-lo antes que a coleção inteira seja retornada, ao contrário deGetFiles()
onde você precisa carregar a coleção inteira na memória antes de começar a enumerá-la. Veja esta citação aqui :O mesmo se aplica a
EnumerateDirectories()
eGetDirectories()
. Portanto, o código seria:Para os fins desta pergunta, não há realmente nenhuma razão para usar
GetFiles()
eGetDirectories()
.fonte
Directory.Delete(path, true)
vai cuidar de tudo :)file.Delete()
.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.
Isso permitirá que você faça algo como ..
fonte
Empty
existe em C # parastring
. Se eu visse outra coisa chamadaEmpty
, ficaria surpreso se ele modificasse o objeto (ou sistema de arquivos) em vez de fornecer umbool
que diz se está vazio ou não. Por causa disso, eu iria com o nomeClean
.Is
(ou seja, emIsEmpty
vez deEmpty
).O código a seguir limpará a pasta recursivamente:
fonte
fonte
Delete
será lançado se o diretório não existir, portanto, seria mais seguro fazer umaDirectory.Exists
verificação primeiro.Directory.Exists
não é suficiente; após a verificação, outro segmento pode ter renomeado ou removido o diretório. É mais segurotry-catch
.Directory.Create
porque o recursivaDirectory.Delete
infelizmente não é garantido para ser síncrono ..Também podemos mostrar amor pelo LINQ :
Observe que minha solução aqui não tem desempenho, porque estou usando o
Get*().ToList().ForEach(...)
que gera o mesmoIEnumerable
duas vezes. Eu uso um método de extensão para evitar esse problema:Este é o método de extensão:
fonte
foreach (var dir in info.GetDirectories("*", SearchOption.AllDirectories).OrderByDescending(dir => dir.FullName.Length)) dir.Delete();
pode ser útil.directory.EnumerateFiles()
edirectory.EnumerateDirectories()
não osdirectory.Get*()
métodos.IEnumerable<T>.ForEach()
extensão possui um comentário XML resumido, "Violação! Violação! Imundo!".A maneira mais simples:
Esteja ciente de que isso pode acabar com algumas permissões na pasta.
fonte
Se você sabe que não há subpastas, algo como isto pode ser o mais fácil:
fonte
fonte
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.
fonte
Aqui está a ferramenta com a qual terminei depois de ler todas as postagens. Faz
Lida com
Ele não usa Directory.Delete porque o processo é interrompido por exceção.
fonte
O código a seguir limpará o diretório, mas deixará o diretório raiz (recursivo).
fonte
eu usei
para excluir imagens antigas e não preciso de nenhum objeto nesta pasta
fonte
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.
fonte
fonte
fonte
No Windows 7, se você acabou de criar manualmente com o Windows Explorer, a estrutura de diretórios é semelhante a esta:
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:
fonte
Esta versão não usa chamadas recursivas e resolve o problema somente leitura.
fonte
use o método GetDirectories do DirectoryInfo.
fonte
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);
:É obtido em https://msdn.microsoft.com/en-us/library/fxeahc5f(v=vs.110).aspx .
fonte
Não é a melhor maneira de lidar com o problema acima. Mas é uma alternativa ...
fonte
fonte
isso mostrará como excluímos a pasta e verificamos se usamos a caixa de texto
fonte
fonte
Chamada do principal
Adicione este método
fonte
fonte
Para excluir a pasta, este é o código usando a caixa de texto e um botão
using System.IO;
:fonte
fonte
Directory.CreateDirectory
A única coisa que você deve fazer é definir
optional recursive parameter
aTrue
.Directory.Delete("C:\MyDummyDirectory", True)
Graças ao .NET. :)
fonte
Você não precisa de mais do que isso
fonte