如何删除目录中的所有文件和文件夹?


662

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


11
如果DirectoryInfo具有.Clean();这样的方法,那会很好。
JL。

6
或.DeleteFolders和DeleteFiles方法。
JL。

18
您想知道,如果文件被锁定(或者您没有权限),则删除操作很容易引发异常。请参阅FileInfo.Delete以获取例外列表。
Shane Courtrille 09年

Answers:


831
System.IO.DirectoryInfo di = new DirectoryInfo("YourPath");

foreach (FileInfo file in di.GetFiles())
{
    file.Delete(); 
}
foreach (DirectoryInfo dir in di.GetDirectories())
{
    dir.Delete(true); 
}

如果您的目录可能包含许多文件,EnumerateFiles()则效率要高于GetFiles(),因为使用EnumerateFiles()时可以在返回GetFiles()整个集合之前开始枚举,而不是在开始枚举之前需要在内存中加载整个集合。在这里看到这个报价:

因此,当您处理许多文件和目录时,EnumerateFiles()会更高效。

EnumerateDirectories()和和相同GetDirectories()。因此,代码将是:

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

出于这个问题的目的,实际上没有理由使用GetFiles()GetDirectories()


6
什么是stackoverflow.com/questions/12415105/… “当您调用Directory.Delete并以这种方式打开文件时,Directory.Delete成功删除所有文件,但是当Directory.Delete调用RemoveDirectory时“目录不为空”由于存在一个标记为删除但实际上未删除的文件,因此引发了异常。”
Kiquenet

74
DirectoryInfo速度很慢,因为它会收集更多其他数据。顺便说一句: Directory.Delete(path, true)将照顾一切:)
AcidJunkie

57
@AcidJunkie,这也会删除有问题的目录,而OP专门要求保留根目录。
Marc L.

5
请注意,如果任何文件均为只读,则此方法将无效。您需要在调用之前删除只读标志file.Delete()
2015年

8
如果子目录包含文件,这似乎不起作用。
cdiggins

174

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

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

4
最后一行应该是subDirectory.Delete(true)而不是directory.Delete(true)。我只是剪切并粘贴了代码,然后删除了主目录本身。感谢您的代码,它很棒!
Aximili 2010年

26
请注意,Empty已经存在于C#中string。如果我看到其他命名的东西,Empty如果它修改了对象(或文件系统)而不是给我一个bool说它是否为空的信息,我会感到惊讶。因此,我将使用这个名字Clean
默认值

5
@Default:我不认为一种类型已经具有属性这一事实不应该影响另一种(完全不相关的)类型;指示也可以是动词的单词的状态的属性和函数的约定是在它们之前加上前缀Is(即IsEmpty而不是Empty)。
亚当·罗宾逊

3
@AdamRobinson只是想记下它。对我而言,微软在其代码中所拥有的确实具有一定的意义。但这是每个人都可以解释的:)
默认值

4
@simonhaines:问题的关键是清空目录(即删除其中的所有内容),而不是删除目录本身。
亚当·鲁滨逊

77

以下代码将递归清除文件夹:

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

为我工作,而Directory.Delete(path,true); 引发抱怨该文件夹不是空的
杰克·格里芬

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

 //Or

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

1
第二个选项Directory.Delete(String,Boolean)为我工作。
Stephen MacDougall

15
这将删除根目录,OP明确要求保留该根目录。
Marc L.

2
Delete如果该目录不存在,则会抛出该错误,因此首先进行Directory.Exists检查会更安全。
詹姆斯

1
@James Directory.Exists还不够;检查后,另一个线程可能已重命名或删除了目录。这样做比较安全try-catch
andre_ss6

2
@Marv小心地添加了一个,Directory.Create因为Directory.Delete遗憾的是不能保证递归是同步的。–
Andrew Hanlon

38

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

1
而且,如果您也尝试删除子目录,则foreach (var dir in info.GetDirectories("*", SearchOption.AllDirectories).OrderByDescending(dir => dir.FullName.Length)) dir.Delete();可能有用。
Warty 2014年

1
如果您喜欢性能,请考虑使用directory.EnumerateFiles()directory.EnumerateDirectories()代替directory.Get*()方法。
Tinister

1
有趣的是,我自己的IEnumerable<T>.ForEach()扩展名中有一个摘要XML注释:“违反!违反!不干净!”。
Marc L.

嘿,第二个原因是什么?第三?等等。?
比尔·罗伯茨

大声笑@RASX-他正在与您交谈:“如果您不同意这些哲学上的反对意见,并在这种模式下发现实际价值,请务必继续编写此琐碎的单行代码。”
比尔·罗伯茨

37

最简单的方法:

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

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


9
请注意,这将删除路径拥有的所有特殊权限
Matthew Lock

6
您需要在这两个动作之间添加超时。尝试运行此代码,您将得到异常:while(true){Directory.Delete(@“ C:\ Myfolder”,true); Directory.CreateDirectory(@“ C:\ Myfolder”); }
RcMan

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

如果您知道没有子文件夹,则可能是最简单的事情:

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

我使用此功能来清除系统临时文件夹。我只是在Delete()和IsReadOnly周围添加了try-catch来忽略所有异常,并且它起作用了。
汉巴德,

@humbads,您可以更新此答案,还是将代码放在此处,我将通过您的更改进行更新?
zumalifeguard

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

3
与上述相同:请注意,这将删除路径具有的所有特殊权限。
hB0

8

我尝试的每种方法在某些时候都因System.IO错误而失败。即使文件夹是否为空,是否为只读等,也可以肯定使用以下方法。

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
在清空目录时,我总是更喜欢rd / s / q + mkdir。
戴维·奥西亚2014年

7
这不是跨平台的解决方案。类似Unix的系统显然没有cmd.exe,甚至没有运行.exe文件。C#不仅是Windows,还有跨平台的Mono。
显示名称

1
@SargeBorsch问题中没有跨平台要求,而作为C#,该解决方案很可能将用于Windows。这似乎是不使用.NET函数的唯一答案,因此作为替代方法,它非常有价值。
亚历克斯·潘德里亚

7

这是我阅读所有帖子后使用的工具。确实

  • 删除所有可以删除的
  • 如果某些文件保留在文件夹中,则返回false

它处理

  • 只读文件
  • 删除延迟
  • 锁定文件

它不使用Directory.Delete,因为该进程在异常中止。

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

以下代码将清除目录,但将根目录保留在此处(递归)。

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


5

仅将静态方法与File和Directory一起使用,而不是FileInfo和DirectoryInfo,将可以更快地执行。(请参见C#中File和FileInfo有什么区别?)的已接受答案。答案显示为实用方法。

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

mscorlib.dll中发生类型'System.IO.IOException'的异常,但未在用户代码中处理。其他信息:目录不为空。
kipusoep

3

在Windows 7中,如果您只是使用Windows资源管理器手动创建的,则目录结构与此类似:

C:
  \AAA
    \BBB
      \CCC
        \DDD

并运行原始问题中建议的代码以清理目录C:\ AAA,该行 di.Delete(true)尝试删除BBB时始终失败,并出现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);
    }
}

什么是stackoverflow.com/questions/12415105/… “当您调用Directory.Delete并以这种方式打开文件时,Directory.Delete成功删除所有文件,但是当Directory.Delete调用RemoveDirectory时“目录不为空”由于存在一个标记为删除但实际上未删除的文件,因此引发了异常。”
Kiquenet

@Kiquenet:好像我们在Windows中发现了一个问题。Windows可以查询标记为删除的文件列表,如果目录中的所有文件都标记为删除,则不要说该目录不为空。无论如何,我的WaitForDirectoryToBecomeEmpty()是一种解决方法。
farfareast

2

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

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

使用DirectoryInfo的GetDirectories方法。

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

1

以下示例显示了如何执行此操作。它首先创建一些目录和文件,然后通过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);
        }
    }

它来自https://msdn.microsoft.com/en-us/library/fxeahc5f(v=vs.110).aspx


1

这不是解决上述问题的最佳方法。但这是另一种...

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

您能否更具体一点,并解释一下如何以及为什么要这样做?
Deep Frozen

3
仅使用代码的答案不适合。您应该解释它如何以及为什么应该起作用/解决问题。
rdurand

0

这将显示我们如何删除文件夹并检查它,我们使用文本框

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

主电话

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

添加此方法

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

要删除文件夹,这是使用文本框和按钮的代码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
参见下文...“删除和重新创建”与保留不同,所有ACL定制都将丢失。
Marc L.

我已经尝试过类似的操作,因为我不在乎ACL的自定义,并且遇到了以下问题:文件夹创建后未创建Directory.CreateDirectory
SD的JG,

-3

您唯一要做的就是设置optional recursive parameterTrue

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

多亏了.NET。:)


3
这也将删除目录本身。
rajat

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.