Як видалити всі файли та папки в каталозі?


662

Як за допомогою C # можна видалити всі файли та папки з каталогу, але все ж зберігати кореневий каталог?


11
Що було б добре, якби DirectoryInfo мав такий метод, як .Clean ();
JL.

6
або .DeleteFolders та DeleteFiles методи.
JL.

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

Відповіді:


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," каталог не порожній " виняток викидається, оскільки є файл, позначений для видалення, але фактично не видалений. "
Кікенет

74
DirectoryInfo повільний, оскільки він збирає набагато більше інших даних. BTW: Directory.Delete(path, true)подбає про всіх :)
AcidJunkie

57
@AcidJunkie, Це також видалить відповідний каталог, тоді як ОП спеціально просить зберегти кореневий каталог.
Марк Л.

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) замість каталогу.Delete (true). Я просто вирізав і вставив код, і він видалив головний каталог сам. Дякую за код, це чудово!
Аксімілі

26
зауважте, що Emptyіснує вже в C #, для string. Якби я побачив щось інше на ім'я, Emptyя був би здивований, якби він змінив об'єкт (або файлову систему) замість того, щоб дати мені boolте, що говорить, чи воно порожнє чи ні. Через це я пішов би з прізвищем Clean.
За замовчуванням

5
@ За замовчуванням: я не думаю, що факт, що один тип має властивість, вже не повинен мати жодного відношення до того, чи має його мати інший (абсолютно не пов'язаний) тип; а умовою властивостей і функцій, які вказують стан слів, які також можуть бути дієсловами, є префікс їх 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 (шлях, правда); кинув скарги, що папка не спорожніла
Джек Гриффін

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

 //Or

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

1
Другий варіант, Directory.Delete (String, Boolean) працював для мене.
Стівен Макдугалл

15
Це видаляє кореневий каталог, де ОП спеціально просить його зберегти.
Марк Л.

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

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

2
@Marv Обережно з просто додаванням, Directory.Createоскільки рекурсивна Directory.Delete, на жаль, не гарантується синхронністю ..
Ендрю Ханлон

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)

Я використовував цю функцію для очищення папки системних темп. Я щойно додав спробу-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, якщо мова йде про випорожнення каталогів.
Dawid Ohia

7
Це не кросплатформене рішення. У Unix-подібних системах явно немає cmd.exe, вони навіть не запускають .exe файли. C # - це не тільки Windows, також є Mono, яка є кросплатформою.
Відображати ім’я

1
@SargeBorsch у запитанні не було вимоги між платформою, і це C #, швидше за все, рішення буде використано для Windows. Здається, це єдина відповідь, яка не використовує .NET функції, тому вона є досить цінною як альтернатива.
Алекс Пандреа

7

Ось інструмент, яким я закінчив, прочитавши всі пости. Це робить

  • Видаляє все, що можна видалити
  • Повертає помилку, якщо деякі файли залишаються у папці

Це стосується

  • Файли лише для читання
  • Затримка видалення
  • Заблоковані файли

Він не використовує 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);

6

я використав

Directory.GetFiles(picturePath).ToList().ForEach(File.Delete);

для видалення старої картинки, і мені не потрібен жоден об’єкт у цій папці


1
Не впевнений, що вам потрібен .ToList ()
Ben Power

5

Використання лише статичних методів у файлі та каталозі замість 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

це покаже, як ми видаляємо папку і перевіряємо її, ми використовуємо поле Text

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
Це також видаляє сам каталог.
rajat

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

Вам не потрібно більше цього


2
Неправильно ... це також видалить кореневий каталог.
L-Four
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.