Con C #, ¿cómo puedo eliminar todos los archivos y carpetas de un directorio, pero aún así mantener el directorio raíz?
Con C #, ¿cómo puedo eliminar todos los archivos y carpetas de un directorio, pero aún así mantener el directorio raíz?
Respuestas:
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()
.
Directory.Delete(path, true)
se encargará de todo :)
file.Delete()
.
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();
Empty
en cuenta que ya existe en C #, para string
. Si viera algo más llamado, Empty
me sorprendería si modificara el objeto (o el sistema de archivos) en lugar de darme un bool
mensaje que diga si está vacío o no. Por eso, iría con el nombre Clean
.
Is
(es decir, en IsEmpty
lugar de Empty
).
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();
}
}
new System.IO.DirectoryInfo(@"C:\Temp").Delete(true);
//Or
System.IO.Directory.Delete(@"C:\Temp", true);
Delete
lanzará si el directorio no existe, por lo que sería más seguro hacer una Directory.Exists
verificación primero.
Directory.Exists
no es suficiente; después de la verificación, otro hilo puede haber renombrado o eliminado el directorio. Es más seguro try-catch
.
Directory.Create
porque el recursivo Directory.Delete
desafortunadamente no se garantiza que sea sincrónico ..
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 IEnumerable
dos 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);
}
}
}
foreach (var dir in info.GetDirectories("*", SearchOption.AllDirectories).OrderByDescending(dir => dir.FullName.Length)) dir.Delete();
podría ser útil.
directory.EnumerateFiles()
y en directory.EnumerateDirectories()
lugar de los directory.Get*()
métodos.
IEnumerable<T>.ForEach()
extensión tiene un comentario XML de resumen, "¡Violación! ¡Violación! ¡Inmundo!".
La forma más simple:
Directory.Delete(path,true);
Directory.CreateDirectory(path);
Tenga en cuenta que esto puede eliminar algunos permisos en la carpeta.
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)
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);
Aquí está la herramienta con la que terminé después de leer todas las publicaciones. Lo hace
Se trata de
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;
}
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);
solía
Directory.GetFiles(picturePath).ToList().ForEach(File.Delete);
para eliminar la imagen anterior y no necesito ningún objeto en esta carpeta
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);
}
}
string directoryPath = "C:\Temp";
Directory.GetFiles(directoryPath).ToList().ForEach(File.Delete);
Directory.GetDirectories(directoryPath).ToList().ForEach(Directory.Delete);
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);
}
}
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();
}
}
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 .
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]);
}
DirectoryInfo Folder = new DirectoryInfo(Server.MapPath(path));
if (Folder .Exists)
{
foreach (FileInfo fl in Folder .GetFiles())
{
fl.Delete();
}
Folder .Delete();
}
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();
}
}
}
using System.IO;
string[] filePaths = Directory.GetFiles(@"c:\MyDir\");
foreach (string filePath in filePaths)
File.Delete(filePath);
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);
}
}
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);
}
}
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
}
Directory.CreateDirectory
IO.Directory.Delete(HttpContext.Current.Server.MapPath(path), True)
No necesitas más que eso