1. Introduction
Imagine a photo archive accumulated over several years — thousands of files in one folder (classic Windows user case), and now picture the task: copy only .jpg files that were created this year into a separate folder for processing. Or you need to rename all reports with the prefix "old_" to distinguish old and new versions. Even if you’re far from photo archives, mass operations are needed in almost any project involving data processing, logs, backups or automation. They also come up in interviews!
Mass operations are a great opportunity to learn:
- Loops and LINQ for iterating directory contents
- Practical work with paths (Path)
- Basics of filtering, searching, pattern-based renaming
- Important topics: security, errors, overwrites
Let’s go — and may the force be with you to conquer file chaos!
2. Bulk copying files
How it works: general principle
For a mass operation you usually need to:
- Get a list of the files you need (for example, all .txt in a folder)
- For each file perform the required action (copy, delete, etc.)
You can implement this via:
- Directory.GetFiles() — to get a list of files,
- A foreach loop — to iterate each file and perform the needed operation.
Example: copying all .txt files from one folder to another
string sourceDir = @"C:\Source";
string destDir = @"C:\Target";
// Get a list of all .txt files in the source folder
string[] txtFiles = Directory.GetFiles(sourceDir, "*.txt");
foreach (string srcPath in txtFiles)
{
// Get only the file name from the full path
string fileName = Path.GetFileName(srcPath);
// Build the full path for the file in the target folder
string destPath = Path.Combine(destDir, fileName);
// Copy the file
File.Copy(srcPath, destPath, overwrite: true); // overwrite - if the file already exists, replace it
Console.WriteLine($"Copied: {fileName}");
}
Console.WriteLine("All .txt files were successfully copied!");
Note: in this example we use the filter "*.txt" — that's the filename search pattern, same as in Windows.
Visualization (diagram)
+----------------+ [*.txt] +----------------+
| C:\Source | ---filter-----> | C:\Target |
| a.txt | foreach + | |
| b.txt | --copy--------> | a.txt (copied) |
| c.jpg | | b.txt (copied) |
+----------------+ +----------------+
(.jpg files are ignored, only .txt are copied)
3. Bulk deleting files
Bulk deleting files is a very common operation. For example, you often need to clean temporary files, automatically delete old logs or jpg photos you no longer need.
Example: delete all files older than 30 days
string dir = @"C:\MyLogs";
int daysOld = 30;
DirectoryInfo di = new DirectoryInfo(dir);
// Get all files in the folder
foreach (FileInfo file in di.GetFiles())
{
// Check the last write time
if (file.LastWriteTime < DateTime.Now.AddDays(-daysOld))
{
file.Delete();
Console.WriteLine($"Deleted: {file.Name}");
}
}
Tip: FileInfo.LastWriteTime — very convenient for "older than N days" checks.
4. Bulk renaming files
Sometimes you need to rename many files by a pattern. For example, add a common prefix, change extensions, or just number everything. In .NET it's the same approach — get the list of files, then rename them using File.Move().
Example: add the prefix "old_" to all .docx files
string dir = @"C:\Reports";
string[] docxFiles = Directory.GetFiles(dir, "*.docx");
foreach (string oldPath in docxFiles)
{
string dirPath = Path.GetDirectoryName(oldPath)!;
string fileName = Path.GetFileName(oldPath);
string newPath = Path.Combine(dirPath, "old_" + fileName);
// Rename (actually, move to the same folder with a new name)
File.Move(oldPath, newPath);
Console.WriteLine($"Renamed: {fileName} -> old_{fileName}");
}
Important point: if the folder already contains a file with the new name, an exception will be thrown. You can handle it with try-catch if needed.
5. Copying whole directories with all contents
For simple single-folder operations there is no built-in "copy whole folder" one-liner (Directory.Copy doesn't exist — a trap for the unwary!). You need to copy manually:
- Create the target folder (if it doesn't exist)
- Copy all files (see the familiar example)
- Recursively copy all subfolders (treat each as a new copy task)
Universal function: recursive folder copy
using System;
using System.IO;
class Program
{
static void CopyDirectory(string sourceDir, string destDir, bool overwrite = true)
{
// Create the folder if it doesn't exist
Directory.CreateDirectory(destDir);
// Copy all files
foreach (string filePath in Directory.GetFiles(sourceDir))
{
string fileName = Path.GetFileName(filePath);
string destFile = Path.Combine(destDir, fileName);
File.Copy(filePath, destFile, overwrite);
}
// Copy all subfolders (recursively)
foreach (string subDir in Directory.GetDirectories(sourceDir))
{
string dirName = Path.GetFileName(subDir);
string destSubDir = Path.Combine(destDir, dirName);
CopyDirectory(subDir, destSubDir, overwrite);
}
}
static void Main()
{
string source = @"C:\Archive2023";
string target = @"D:\Backup2023";
CopyDirectory(source, target);
Console.WriteLine("Directory was successfully copied!");
}
}
Flowchart
CopyDirectory(A, B)
/ \
copy files foreach subDir -> CopyDirectory(subDir, destSubDir)
6. Bulk filtering, searching and processing files
Suppose you want not just to iterate a folder but select by multiple criteria: for example, only images whose size is over 5 MB and were created in 2024! It's convenient to combine LINQ with filesystem classes for that.
Example: print names of large and recent images
string dir = @"C:\Pictures";
var filtered = new DirectoryInfo(dir)
.GetFiles("*.jpg")
.Where(f => f.Length > 5_000_000 && f.CreationTime.Year == 2024);
foreach (var file in filtered)
{
Console.WriteLine($"{file.Name} ({file.Length / 1024 / 1024} MB)");
}
In this example we use LINQ for chaining filters — writing realistic code you'll see in real work.
7. Walking nested folders: recursion and enumeration
Often you need to handle not just one directory but all nested ones too (for example, delete all temporary files across an archive tree). The file-getting methods (Directory.GetFiles and DirectoryInfo.GetFiles) have an overload with the SearchOption.AllDirectories parameter that does this for you!
Example: find and delete all .tmp files in all subfolders
string root = @"D:\BigFolder";
string[] tmpFiles = Directory.GetFiles(root, "*.tmp", SearchOption.AllDirectories);
foreach (string file in tmpFiles)
{
File.Delete(file);
Console.WriteLine($"Deleted: {file}");
}
Console.WriteLine("All temporary files have been deleted.");
Warning: Be careful with this flag — it can find files even in very deep nested structures!
8. Bulk creating files and directories
Sometimes the task is the opposite — automatically create the required directory structure or generate many files.
Example: create 10 folders and 10 files in each
string root = @"C:\GeneratedFolders";
for (int i = 1; i <= 10; i++)
{
string subDir = Path.Combine(root, $"Folder_{i}");
Directory.CreateDirectory(subDir);
for (int j = 1; j <= 10; j++)
{
string filePath = Path.Combine(subDir, $"File_{j}.txt");
File.WriteAllText(filePath, $"This is file number {j} in folder {i}");
}
}
Console.WriteLine("Folders and files created!");
Tip: You can quickly build test infrastructure, generate "fake" data for tests, training, etc.
9. Bulk moving files
Similar to copying, but use File.Move instead of File.Copy. Good for sorting files into folders.
Example: sort files by extensions
Imagine this: a folder full of files of various types, and you want to sort them into folders .jpg, .pdf, .docx, etc.
string source = @"C:\Downloads";
string[] files = Directory.GetFiles(source);
foreach (string path in files)
{
string ext = Path.GetExtension(path).TrimStart('.').ToUpper(); // "JPG", "PDF", "DOCX"
if (string.IsNullOrEmpty(ext)) ext = "OTHER";
string destDir = Path.Combine(source, ext);
Directory.CreateDirectory(destDir); // fine if it already exists
string fileName = Path.GetFileName(path);
string destPath = Path.Combine(destDir, fileName);
if (!File.Exists(destPath))
{
File.Move(path, destPath);
Console.WriteLine($"Moved: {fileName} -> {destDir}");
}
else
{
Console.WriteLine($"File already exists in {destDir}, skipping: {fileName}");
}
}
The files will be sorted into "boxes", and you'll feel like a digital Marie Kondo.
10. Common mistakes and nuances of bulk operations
When you work with hundreds instead of one file, interesting details pop up.
For example, some files might be open by another program — attempts to delete or copy them will fail. Also common: the target folder already contains a file with the desired name. If your code doesn’t allow overwriting, it will throw. Sometimes files or folders are inaccessible due to permissions, or you might accidentally delete something important recursively.
A classic mistake is performing operations without error handling: if a failure occurs halfway (for example, lack of rights on one file), the loop will break and the rest won't be processed. So for reliable bulk operations you almost always use exception handling with try-catch inside the loop, so a problematic file can be skipped and the rest still processed.
And don't forget about overwrite options: where appropriate, use overwrite: true in File.Copy, and when renaming/moving check whether the destination file exists in advance or implement a conflict strategy (rename with suffix, skip, logging).
GO TO FULL VERSION