Question
Using C#, how can I delete every file and subdirectory inside a directory while keeping the root directory itself intact?
Short Answer
You will learn how C# represents directories and files, how to delete a directory's immediate contents safely, and why deleting the root directory is different from clearing it. You will also see practical patterns for validation, error handling, and recursive deletion.
Concept
A directory has two separate parts:
- The root directory: the folder whose path you start with.
- Its contents: files and nested subdirectories inside that folder.
To keep the root directory, delete its contents individually rather than calling Directory.Delete on the root path.
In C#, DirectoryInfo provides object-oriented methods for inspecting a folder:
GetFiles()returns files directly inside the directory.GetDirectories()returns subdirectories directly inside it.FileInfo.Delete()deletes one file.DirectoryInfo.Delete(true)deletes a directory and everything beneath it recursively.
This distinction matters in applications that use a permanent working folder, such as a cache, upload staging area, export location, or temporary report directory. The application may expect that root folder to remain available after cleanup.
Mental Model
Think of the root directory as a cupboard and its contents as papers and smaller boxes inside it.
- Deleting a file removes one paper.
- Deleting a subdirectory recursively removes a smaller box and everything in it.
- The cupboard stays in place because you never delete the cupboard itself.
Calling Directory.Delete(rootPath, true) is different: it removes the entire cupboard, not just what is inside it.
Syntax and Examples
Use DirectoryInfo to get the root folder's direct children, then delete each child.
using System;
using System.IO;
string rootPath = @"C:\Temp\Work";
DirectoryInfo root = new DirectoryInfo(rootPath);
if (!root.Exists)
{
throw new DirectoryNotFoundException($"Directory not found: {rootPath}");
}
foreach (FileInfo file in root.GetFiles())
{
file.Delete();
}
foreach (DirectoryInfo directory in root.GetDirectories())
{
directory.Delete(recursive: true);
}
root.GetFiles() gets files directly in C:\Temp\Work, and file.Delete() removes them.
root.GetDirectories() gets only the direct child folders. Passing recursive: true to directory.Delete deletes each child folder along with all files and folders nested inside it.
The root variable is never deleted, so C:\Temp\Work remains after the cleanup.
Step by Step Execution
Consider this folder structure:
C:\Temp\Work
├── notes.txt
├── output.csv
└── Archive
├── old.txt
└── Images
└── logo.png
Code:
DirectoryInfo root = new DirectoryInfo(@"C:\Temp\Work");
foreach (FileInfo file in root.GetFiles())
{
file.Delete();
}
foreach (DirectoryInfo directory in root.GetDirectories())
{
directory.Delete(true);
}
Execution:
new DirectoryInfo(...)creates an object representingC:\Temp\Work. It does not delete or create anything yet.GetFiles()returnsnotes.txtandoutput.csv.- The first loop deletes both files.
GetDirectories()returnsArchive.Archive.Delete(true)deletesArchive,old.txt,Images, andlogo.png.C:\Temp\Workstill exists, but it is now empty.
Real World Use Cases
Common reasons to clear a folder while retaining it include:
- Application caches: remove cached thumbnails or downloaded data before rebuilding them.
- Upload staging folders: clear files from a previous processing job before accepting a new upload.
- Report exports: remove old CSV or PDF exports before generating the latest set.
- Build or test artifacts: clean generated output before a build or integration test.
- Scheduled maintenance: clear a known temporary workspace without changing its configured path.
In all cases, use a path controlled by your application. Avoid deleting a path supplied directly by an untrusted user.
Real Codebase Usage
Production code usually wraps cleanup in a method that validates the path and handles expected failures.
using System;
using System.IO;
public static class DirectoryCleaner
{
public static void ClearContents(string rootPath)
{
if (string.IsNullOrWhiteSpace(rootPath))
{
throw new ArgumentException("A directory path is required.", nameof(rootPath));
}
DirectoryInfo root = new DirectoryInfo(rootPath);
if (!root.Exists)
{
return; // Nothing to clean.
}
foreach (FileInfo file in root.GetFiles())
{
file.Delete();
}
foreach (DirectoryInfo directory in root.GetDirectories())
{
directory.Delete(recursive: true);
}
}
}
Useful real-project practices:
- Use a guard clause to reject missing or invalid input early.
- Treat a missing cleanup directory as a no-op when that fits the application.
- Log
UnauthorizedAccessExceptionorIOExceptionif cleanup is best-effort rather than critical. - Ensure the path is an intended application workspace before deleting anything.
- Do not delete files that are still open by your own process; dispose streams first with
using.
Common Mistakes
Deleting the root directory accidentally
This deletes the root folder too:
Directory.Delete(rootPath, recursive: true);
Use this only when you explicitly want to remove rootPath. To retain it, enumerate and delete its children instead.
Forgetting recursive deletion for child folders
This works only if subdirectory is empty:
subdirectory.Delete();
Use recursive deletion for a child directory that may contain files:
subdirectory.Delete(recursive: true);
Assuming GetFiles() includes nested files
foreach (FileInfo file in root.GetFiles())
{
file.Delete();
}
This deletes only files directly in root; it does not delete files inside child folders. Delete the child folders recursively as well.
Ignoring locked files and permissions
A file can fail to delete because another process is using it, or because the application lacks permission. File operations can throw exceptions such as:
UnauthorizedAccessExceptionIOException
Handle or report these errors according to your application's requirements. Do not silently ignore failures when complete cleanup is required.
Using a dangerous path
Never run recursive deletion against a path unless you have verified it is the intended workspace. A typo in a configured path can delete important data.
Comparisons
| Approach | Keeps the root directory? | Deletes nested contents? | Best use |
|---|---|---|---|
| Loop through files and child directories | Yes | Yes, when child directories use Delete(true) | Clear an existing workspace |
Directory.Delete(rootPath, true) | No | Yes | Remove the root directory completely |
Delete root, then Directory.CreateDirectory(rootPath) | Eventually yes | Yes | Sometimes used for a full reset, but has a period where the folder does not exist |
Delete only files with GetFiles() | Yes | No | Clear files only and preserve subfolders |
DirectoryInfo and the static Directory class can both perform directory work. DirectoryInfo is convenient here because GetFiles() returns FileInfo objects and GetDirectories() returns DirectoryInfo objects, each with its own Delete method.
Cheat Sheet
using System.IO;
DirectoryInfo root = new DirectoryInfo(rootPath);
if (root.Exists)
{
foreach (FileInfo file in root.GetFiles())
{
file.Delete();
}
foreach (DirectoryInfo directory in root.GetDirectories())
{
directory.Delete(recursive: true);
}
}
GetFiles()returns files directly inside a directory.GetDirectories()returns direct child directories.file.Delete()deletes one file.directory.Delete(true)deletes a directory and all descendants.Directory.Delete(rootPath, true)also deletes the root itself.- Check
Existsbefore cleanup when a missing directory is acceptable. - Expect permission and file-lock failures in real environments.
FAQ
How do I delete all files in a directory but not its subfolders in C#?
Use root.GetFiles() and call Delete() for each returned file. Do not loop through root.GetDirectories().
Does GetFiles() search subdirectories automatically?
No. GetFiles() without a search option returns only files directly in the specified directory.
Does DirectoryInfo.Delete(true) delete the directory itself?
Yes. When called on a child directory, it deletes that child and everything below it. When called on the root directory, it deletes the root too.
What happens if the directory does not exist?
new DirectoryInfo(path) does not fail merely because the directory is missing, but accessing its contents can fail. Check root.Exists first if the directory may be absent.
Why does file deletion throw an IOException?
Common causes include a file being open by another process, a temporary system lock, or an I/O problem. Close streams and retry or report the error as appropriate.
Can I clear a directory with Directory.Delete and recreate it?
Yes, but it briefly removes the root directory. Deleting children is usually preferable when other code expects the root to remain present.
Is recursive deletion safe?
It is safe only when the target path has been carefully validated. Recursive deletion can remove a large amount of data quickly.
Mini Project
Description
Build a small console cleanup utility for a temporary workspace. It ensures the workspace exists, removes every file and nested folder inside it, and leaves the workspace ready for the next task.
Goal
Create a C# console program that clears a chosen workspace directory without deleting the workspace itself.
Requirements
Ensure the workspace directory exists before cleanup.
Delete every file directly inside the workspace.
Delete every subdirectory and all of its contents.
Print a confirmation that the root workspace still exists.
Use a clearly named workspace path that can be changed safely.
Keep learning
Related questions
AddTransient vs AddScoped vs AddSingleton in ASP.NET Core Dependency Injection
Learn the differences between AddTransient, AddScoped, and AddSingleton in ASP.NET Core DI with examples and practical usage.
Best Way to Repeat a Character in C#: Building Repeated Strings Efficiently
Learn the best way to repeat a character in C#, compare StringBuilder, string concatenation, and simpler built-in options.
C# Access Modifiers and static: public, private, protected, and Defaults
Learn how C# public, private, protected, and default access control visibility, and how static differs from instance members.