En utilisant C #, comment puis-je supprimer tous les fichiers et dossiers d'un répertoire, tout en conservant le répertoire racine?
En utilisant C #, comment puis-je supprimer tous les fichiers et dossiers d'un répertoire, tout en conservant le répertoire racine?
Réponses:
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()
.
Directory.Delete(path, true)
s'occupera de tout :)
file.Delete()
.
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();
Empty
existe déjà en C #, pour string
. Si je voyais quelque chose d'autre nommé Empty
je serais surpris s'il modifiait l'objet (ou le système de fichiers) au lieu de me donner un bool
qui dit s'il est vide ou non. Pour cette raison, j'irais avec le nom Clean
.
Is
(c'est-à-dire IsEmpty
plutôt que Empty
).
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();
}
}
new System.IO.DirectoryInfo(@"C:\Temp").Delete(true);
//Or
System.IO.Directory.Delete(@"C:\Temp", true);
Delete
jettera si le répertoire n'existe pas, il serait donc plus sûr de faire une Directory.Exists
vérification en premier.
Directory.Exists
n'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
.
Directory.Create
car le récursif Directory.Delete
n'est malheureusement pas garanti d'être synchrone ..
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 IEnumerable
deux 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);
}
}
}
foreach (var dir in info.GetDirectories("*", SearchOption.AllDirectories).OrderByDescending(dir => dir.FullName.Length)) dir.Delete();
pourrait être utile.
directory.EnumerateFiles()
et directory.EnumerateDirectories()
au lieu des directory.Get*()
méthodes.
IEnumerable<T>.ForEach()
extension a un commentaire XML résumé, "Violation! Violation! Impur!".
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.
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)
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);
Voici l'outil avec lequel j'ai terminé après avoir lu tous les articles. Cela fait
Ça parle de
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;
}
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);
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
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);
}
}
string directoryPath = "C:\Temp";
Directory.GetFiles(directoryPath).ToList().ForEach(File.Delete);
Directory.GetDirectories(directoryPath).ToList().ForEach(Directory.Delete);
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);
}
}
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();
}
}
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 .
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]);
}
DirectoryInfo Folder = new DirectoryInfo(Server.MapPath(path));
if (Folder .Exists)
{
foreach (FileInfo fl in Folder .GetFiles())
{
fl.Delete();
}
Folder .Delete();
}
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();
}
}
}
using System.IO;
string[] filePaths = Directory.GetFiles(@"c:\MyDir\");
foreach (string filePath in filePaths)
File.Delete(filePath);
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);
}
}
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);
}
}
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)
Tu n'as pas besoin de plus que ça