JavaRush /Курси /C# SELF /Масові операції з файлами

Масові операції з файлами

C# SELF
Рівень 40 , Лекція 4
Відкрита

1. Вступ

Уявіть собі архів фотографій за кілька років — тисячі файлів в одному каталозі (типова ситуація для користувача Windows). А тепер уявіть завдання: скопіювати лише .jpg-файли, створені цього року, до окремого каталогу для обробки. Або вам потрібно перейменувати всі звіти з префіксом "old_", щоб розрізняти стару й нову версії. Навіть якщо ви далекі від архівів фото, масові операції потрібні майже в будь-якому проєкті з обробкою даних, журналів, резервних копій чи автоматизації. Такі завдання трапляються й на співбесідах!

Масові операції — чудова нагода прокачати:

  • Цикли та LINQ для перебору вмісту каталогів
  • Навички роботи зі шляхами (Path)
  • Основи фільтрування, пошуку й шаблонного перейменування
  • Важливі аспекти: безпека, помилки, перезапис

Почнімо — і хай із вами буде сила впорядковувати файловий хаос!

2. Масове копіювання файлів

Як це влаштовано: загальний принцип

Для масової операції зазвичай потрібно:

  1. Отримати список потрібних файлів (наприклад, усі .txt у каталозі)
  2. Для кожного файлу виконати потрібну дію (копіювання, видалення тощо)

Це можна реалізувати через:

  • 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 немає — це пастка для джедаїв!). Доводиться копіювати вручну:

  1. Створити цільовий каталог (якщо його немає)
  2. Скопіювати всі файли (дивіться знайомий нам приклад)
  3. Рекурсивно скопіювати всі підкаталоги (кожен обробляємо як нове завдання копіювання)

Універсальна функція: копіювання каталогу рекурсивно


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

1
Опитування
Створення та видалення файлів, рівень 40, лекція 4
Недоступний
Створення та видалення файлів
Керування файлами та директоріями
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ