Как удалить все файлы и папки в каталоге?


663

Используя C #, как я могу удалить все файлы и папки из каталога, но при этом сохранить корневой каталог?


11
Что было бы хорошо, если бы в DirectoryInfo был такой метод, как .Clean ();
JL.

6
или .DeleteFolders и методы DeleteFiles.
JL.

18
Вы хотите знать, что ваши Удаленные могут очень легко вызвать исключение, если файл заблокирован (или если у вас нет прав). Посмотрите FileInfo.Delete для списка исключений.
Шейн Кортрилл

Ответы:


834
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,« каталог не пуст » генерируется исключение, поскольку существует файл, помеченный для удаления, но фактически не удаленный. "
Кикенет

74
DirectoryInfo работает медленно, так как собирает гораздо больше других данных. Кстати: Directory.Delete(path, true)обо всем позаботится :)
AcidJunkie

57
@AcidJunkie, это также удалит рассматриваемый каталог, тогда как OP специально просит сохранить корневой каталог.
Марк Л.

5
Обратите внимание, что это не будет работать, если любой из файлов доступен только для чтения. Вы должны удалить флаг только для чтения перед вызовом file.Delete().
Бен

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). Я просто вырезал и вставил код, и он удалил сам основной каталог. Спасибо за код, это здорово!
Аксимили

26
обратите внимание, что уже Emptyсуществует в C #, для string. Если бы я увидел что-то другое по имени, Emptyя бы удивился, если бы он изменил объект (или файловую систему) вместо того, чтобы дать мне сообщение, boolкоторое говорит, пусто оно или нет. Из-за этого я бы пошел с именем Clean.
По умолчанию

5
@Default: я не думаю, что тот факт, что один тип уже имеет свойство, должен иметь какое-либо отношение к тому, должно ли оно иметь другой (совершенно не связанный) тип; и условием для свойств и функций, которые указывают состояние слов, которые также могут быть глаголами, является их префикс Is(то есть, IsEmptyа не Empty).
Адам Робинсон

3
@AdamRobinson Просто хотел это отметить. Для меня то , что Microsoft имеет в своем коде, имеет какое-то отношение. Но это все могут интерпретировать :)
По умолчанию

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 (путь, правда); бросил жаловаться, что в папке не было empy
Джек Гриффин

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

 //Or

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

1
Второй вариант, Directory.Delete (String, Boolean) работал для меня.
Стивен МакДугалл

15
Это удаляет корневой каталог, в котором OP специально попросил его сохранить.
Марк Л.

2
Deleteсгенерирует, если каталог не существует, так что было бы безопаснее Directory.Existsсначала сделать проверку.
Джеймс

1
@James Directory.Existsнедостаточно; после проверки другой поток мог переименовать или удалить каталог. Это безопаснее try-catch.
andre_ss6

2
@Marv Осторожнее с простым добавлением a, 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

1
Если вам нравится производительность, подумайте об использовании directory.EnumerateFiles()и directory.EnumerateDirectories()вместо directory.Get*()методов.
Тинистер

1
Забавно, мое собственное IEnumerable<T>.ForEach()расширение содержит краткий XML-комментарий «Нарушение! Нарушение! Нечистый!».
Марк Л.

Эй, какая вторая причина? 3-й? Так далее.?
Билл Робертс

LOL @RASX - он говорит с тобой: «Если ты не согласен с этими философскими возражениями и находишь практическую ценность в этом шаблоне, во что бы то ни стало, иди сам и напиши этот тривиальный однострочник».
Билл Робертс

37

Самый простой способ:

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

Имейте в виду, что это может уничтожить некоторые разрешения для папки.


9
знать, что это удалит любые специальные разрешения, которые имел путь
Мэтью Локк

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)

Я использовал эту функцию, чтобы очистить системную временную папку. Я просто добавил try-catch вокруг Delete () и IsReadOnly, чтобы игнорировать все исключения, и это сработало.
хамбадам

@ 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, когда речь идет об очистке каталогов.
Давид Охия

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 будет работать быстрее. (см. принятый ответ в чем разница между File и FileInfo в C #? ). Ответ показан как служебный метод.

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

Исключение типа «System.IO.IOException» возникло в mscorlib.dll, но не было обработано в коде пользователя. Дополнительная информация: Каталог не пустой.
kipusoep

3

В Windows 7, если вы только что создали его вручную с помощью проводника Windows, структура каталогов выглядит примерно так:

C:
  \AAA
    \BBB
      \CCC
        \DDD

При запуске кода, предложенного в исходном вопросе, для очистки каталога C: \ AAA, строка di.Delete(true)всегда завершается с IOException «Каталог не пуст» при попытке удалить BBB. Вероятно, это связано с задержками / кэшированием в проводнике 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: похоже, мы нашли проблему в 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

используйте метод GetDirectories DirectoryInfo.

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

Не могли бы вы быть более конкретным и объяснить, как и почему это должно работать?
глубоко заморожено

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 будут потеряны.
Марк Л.

Я попробовал что-то очень похожее на это, так как меня не заботили настройки ACL и я столкнулся с проблемами из-за того, что папка не создавалась послеDirectory.CreateDirectory
JG в SD,

-3

Единственное , что вы должны сделать , это установить optional recursive parameterна True.

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

Благодаря .NET. :)


3
Это также удаляет сам каталог.
Раджат

-4
IO.Directory.Delete(HttpContext.Current.Server.MapPath(path), True)

Вам не нужно больше, чем это


2
Неправильно ... это также удалит корневой каталог.
L-Four
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.