使用C#,如何删除目录中的所有文件和文件夹,但仍然保留根目录?


当前回答

是的,这是正确的方法。如果你想给自己一个“干净”(或者,我更喜欢称之为“空”函数),你可以创建一个扩展方法。

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

然后,这将允许您执行以下操作:。。

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

directory.Empty();

其他回答

这不是处理上述问题的最佳方法。但这是另一种选择。。。

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

我们也可以表现出对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));

请注意,我这里的解决方案不是高性能的,因为我使用的是Get*().ToList().ForEach(…),它两次生成相同的IEnumerable。我使用扩展方法来避免此问题:

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

这是扩展方法:

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

最简单的方法:

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

请注意,这可能会删除文件夹上的某些权限。

此版本不使用递归调用,并解决了只读问题。

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

在Windows 7中,如果您刚刚使用Windows资源管理器手动创建了它,则目录结构与以下类似:

C:
  \AAA
    \BBB
      \CCC
        \DDD

运行原始问题中建议的代码来清理目录C:\AAA,当尝试删除BBB时,行di.Delete(true)总是失败,并出现IOException“目录不是空的”。这可能是由于Windows资源管理器中的某种延迟/缓存。

以下代码对我来说工作可靠:

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