1. Вступ
Уявіть собі архів фотографій за кілька років — тисячі файлів в одному каталозі (типова ситуація для користувача Windows). А тепер уявіть завдання: скопіювати лише .jpg-файли, створені цього року, до окремого каталогу для обробки. Або вам потрібно перейменувати всі звіти з префіксом "old_", щоб розрізняти стару й нову версії. Навіть якщо ви далекі від архівів фото, масові операції потрібні майже в будь-якому проєкті з обробкою даних, журналів, резервних копій чи автоматизації. Такі завдання трапляються й на співбесідах!
Масові операції — чудова нагода прокачати:
- Цикли та LINQ для перебору вмісту каталогів
- Навички роботи зі шляхами (Path)
- Основи фільтрування, пошуку й шаблонного перейменування
- Важливі аспекти: безпека, помилки, перезапис
Почнімо — і хай із вами буде сила впорядковувати файловий хаос!
2. Масове копіювання файлів
Як це влаштовано: загальний принцип
Для масової операції зазвичай потрібно:
- Отримати список потрібних файлів (наприклад, усі .txt у каталозі)
- Для кожного файлу виконати потрібну дію (копіювання, видалення тощо)
Це можна реалізувати через:
- Directory.GetFiles() — отримати список файлів,
- Цикл foreach — перебрати кожен файл і виконати потрібну операцію.
Приклад: копіювання всіх .txt-файлів з одного каталогу до іншого
string sourceDir = @"C:\Source";
string destDir = @"C:\Target";
// Отримуємо список усіх .txt файлів у вихідній папці
string[] txtFiles = Directory.GetFiles(sourceDir, "*.txt");
foreach (string srcPath in txtFiles)
{
// Беремо тільки ім'я файлу з повного шляху
string fileName = Path.GetFileName(srcPath);
// Формуємо повний шлях для файлу в цільовій папці
string destPath = Path.Combine(destDir, fileName);
// Копіюємо файл
File.Copy(srcPath, destPath, overwrite: true); // overwrite — якщо файл уже є, замінити
Console.WriteLine($"Copied: {fileName}");
}
Console.WriteLine("Усі .txt файли успішно скопійовано!");
Зверніть увагу: у цьому прикладі ми використовуємо фільтр "*.txt" — це маска пошуку імен файлів, як у Windows.
Візуалізація (схема)
+----------------+ [*.txt] +----------------+
| C:\Source | ---filter-----> | C:\Target |
| a.txt | foreach + | |
| b.txt | --copy--------> | a.txt (copied) |
| c.jpg | | b.txt (copied) |
+----------------+ +----------------+
(.jpg файли ігноруються, копіюються лише .txt)
3. Масове видалення файлів
Масове видалення файлів — доволі популярна операція. Наприклад, часто потрібно проводити чистку тимчасових файлів, автоматичне видалення старих журналів або jpg‑фото, які вам більше не потрібні.
Приклад: видаляємо всі файли старші за 30 днів
string dir = @"C:\MyLogs";
int daysOld = 30;
DirectoryInfo di = new DirectoryInfo(dir);
// Отримуємо всі файли в папці
foreach (FileInfo file in di.GetFiles())
{
// Перевіряємо дату останньої модифікації
if (file.LastWriteTime < DateTime.Now.AddDays(-daysOld))
{
file.Delete();
Console.WriteLine($"Видалено: {file.Name}");
}
}
Зручно: FileInfo.LastWriteTime — ідеально для умов «старші за N днів».
4. Масове перейменування файлів
Іноді потрібно перейменувати багато файлів за шаблоном. Наприклад, додати спільний префікс, змінити розширення або просто пронумерувати все підряд. У .NET це робиться так само — отримуємо список файлів, а потім перейменовуємо їх за допомогою File.Move().
Приклад: додамо префікс "old_" до всіх .docx-файлів
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);
// Перейменовуємо (фактично, це переміщення «у ту саму папку з новою назвою»)
File.Move(oldPath, newPath);
Console.WriteLine($"Перейменовано: {fileName} -> old_{fileName}");
}
Важливий момент: якщо в каталозі вже є файл із новою назвою, виникне виняток. Можна обробити його через try-catch, якщо потрібно.
5. Копіювання цілих каталогів з усім вмістом
Для простих операцій з одним каталогом немає засобу «скопіювати весь каталог» одним рядком (Directory.Copy немає — це пастка для джедаїв!). Доводиться копіювати вручну:
- Створити цільовий каталог (якщо його немає)
- Скопіювати всі файли (дивіться знайомий нам приклад)
- Рекурсивно скопіювати всі підкаталоги (кожен обробляємо як нове завдання копіювання)
Універсальна функція: копіювання каталогу рекурсивно
using System;
using System.IO;
class Program
{
static void CopyDirectory(string sourceDir, string destDir, bool overwrite = true)
{
// Створюємо папку, якщо її немає
Directory.CreateDirectory(destDir);
// Копіюємо всі файли
foreach (string filePath in Directory.GetFiles(sourceDir))
{
string fileName = Path.GetFileName(filePath);
string destFile = Path.Combine(destDir, fileName);
File.Copy(filePath, destFile, overwrite);
}
// Копіюємо всі підпапки (рекурсивно)
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("Директорію успішно скопійовано!");
}
}
Блок-схема
CopyDirectory(A, B)
/ \
copy files foreach subDir -> CopyDirectory(subDir, destSubDir)
6. Масова фільтрація, пошук і обробка файлів
Припустімо, ви хочете не просто перебрати каталог, а відібрати за кількома критеріями: наприклад, лише зображення, розмір яких перевищує 5 МБ, і вони створені у 2024 році! Для цього зручно поєднувати LINQ з класами файлової системи.
Приклад: виводимо імена великих і свіжих зображень
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} МБ)");
}
У цьому прикладі ми використовуємо LINQ для «ланцюжків» фільтрування — тож пишемо реалістичний код, який трапляється на роботі.
7. Обхід вкладених каталогів: рекурсія та перебір
Часто потрібно обробити не лише один каталог, а й усі вкладені (наприклад, видалити всі тимчасові файли по всій структурі архіву). У методів отримання файлів (Directory.GetFiles і DirectoryInfo.GetFiles) є варіант зі спеціальним параметром SearchOption.AllDirectories, який робить це за вас!
Приклад: знайти й видалити всі файли .tmp в усіх підкаталогах
string root = @"D:\BigFolder";
string[] tmpFiles = Directory.GetFiles(root, "*.tmp", SearchOption.AllDirectories);
foreach (string file in tmpFiles)
{
File.Delete(file);
Console.WriteLine($"Видалено: {file}");
}
Console.WriteLine("Усі тимчасові файли видалено.");
Увага: Будьте обережні з цим прапорцем — він може знайти файли навіть у дуже глибоких вкладеннях!
8. Масове створення файлів і каталогів
Інколи завдання зворотне — автоматично створити потрібну структуру каталогів або згенерувати багато файлів.
Приклад: створення 10 каталогів і 10 файлів у кожному
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, $"Це файл номер {j} у папці {i}");
}
}
Console.WriteLine("Папки й файли створено!");
Порада: Так можна швидко збирати тестову інфраструктуру, генерувати «рибу» для тестів, навчання тощо.
9. Масове переміщення файлів
Аналогічно до копіювання: використовуємо File.Move замість File.Copy. Добре підходить для сортування файлів за каталогами.
Приклад: сортуємо файли за розширеннями
Уявімо ситуацію: у каталозі чимало файлів різних типів, і ви хочете розсортувати їх по папках .jpg, .pdf, .docx тощо.
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); // не страшно, якщо вже є
string fileName = Path.GetFileName(path);
string destPath = Path.Combine(destDir, fileName);
if (!File.Exists(destPath))
{
File.Move(path, destPath);
Console.WriteLine($"Переміщено: {fileName} -> {destDir}");
}
else
{
Console.WriteLine($"Файл уже існує у {destDir}, пропускаємо: {fileName}");
}
}
Файли розʼїдуться «по коробках», а ви відчуєте себе Марі Кондо у цифровому світі.
10. Типові помилки й нюанси масових операцій
Коли працюєте не з одним файлом, а з сотнями, виявляються цікаві деталі.
Наприклад, деякі файли можуть бути відкриті іншою програмою — спроба видалити або скопіювати їх призведе до помилки. Часто трапляється, що в цільовому каталозі вже є файл із потрібною назвою. Якщо конструкція не передбачає перезапис, код завершиться винятком. Інколи може бракувати прав доступу до файлів або каталогів, або ви випадково видалите щось важливе рекурсивно.
Класична помилка — виконувати операції без обробки помилок: якщо десь посередині станеться збій (наприклад, відсутність прав на один із файлів), цикл перерветься, і подальші дії не виконаються. Тому для надійних масових операцій майже завжди застосовують обробку винятків через try-catch усередині циклу, щоб проблемний файл можна було пропустити, а решту все ж обробити.
І не забувайте про параметри перезапису: де це доречно, використовуйте overwrite: true у File.Copy, а під час перейменування/переміщення заздалегідь перевіряйте існування файлу за цільовим шляхом або застосовуйте стратегію конфліктів (перейменування з суфіксом, пропуск, журналювання).
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ