C# и файлы: от новичка до мастера работы с файловой системой

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Почему умение работать с файлами в C# — это суперсила?

Представьте, что вы пишете программу, которая должна сохранять настройки пользователя, логировать ошибки или обрабатывать тысячи документов. Без навыков работы с файловой системой вы упрётесь в стену. В C# работа с файлами — это не просто скучное чтение строчек. Это возможность создавать мощные утилиты, парсеры и даже мини-базы данных.

В этой статье мы разберём всё: от банального File.ReadAllText до продвинутой работы с потоками и папками. Вы узнаете, как не потерять данные, как оптимизировать чтение больших файлов и как обходить «подводные камни» файловой системы. Поехали!

Классы-герои: File, FileInfo, Directory и Path

В .NET есть два подхода к работе с файлами: статические методы класса File и экземплярные методы класса FileInfo. Первый — для быстрых операций «прочитал-записал», второй — когда вам нужно работать с одним файлом долго и с сохранением состояния.

File vs FileInfo: когда что использовать?

File — это статический класс. Вы пишете File.Exists("test.txt") — и готово. Удобно, но при каждой операции система проверяет путь заново.

FileInfo — создаёте объект один раз, а потом вызываете методы. Это быстрее, если вы делаете несколько действий с одним файлом.

// Быстрый способ
if (File.Exists(@"C:\data\log.txt"))
{
    string content = File.ReadAllText(@"C:\data\log.txt");
    Console.WriteLine(content);
}

// Профессиональный способ
FileInfo fileInfo = new FileInfo(@"C:\data\log.txt");
if (fileInfo.Exists)
{
    using (StreamReader reader = fileInfo.OpenText())
    {
        string content = reader.ReadToEnd();
        Console.WriteLine(content);
    }
}

Класс Directory работает по тому же принципу — статические методы для быстрых операций с папками. Path — незаменимый помощник для склеивания путей: Path.Combine("folder", "file.txt") автоматически ставит правильный слеш.

Чтение файлов: от малого до гигантского

Чтение файлов в C# — это искусство баланса между простотой и производительностью. Давайте разберём три уровня.

Уровень 1: Всё сразу (для маленьких файлов)

Если файл весит до 10 МБ, смело используйте ReadAllText или ReadAllLines.

string text = File.ReadAllText("config.json");
string[] lines = File.ReadAllLines("users.csv");

Минус: при большом файле вы рискуете получить OutOfMemoryException.

Уровень 2: Построчное чтение (для средних файлов)

Используем StreamReader — читаем строку за строкой, не загружая всё в память.

using (StreamReader reader = new StreamReader("big_log.txt"))
{
    string line;
    while ((line = reader.ReadLine()) != null)
    {
        Console.WriteLine(line); // Обрабатываем каждую строку
    }
}

Обратите внимание на using — он гарантирует, что файл закроется, даже если случится ошибка.

Уровень 3: Чтение бинарных данных (для профи)

Работа с изображениями, архивами или любыми не-текстовыми файлами требует FileStream.

using (FileStream fs = new FileStream("photo.jpg", FileMode.Open, FileAccess.Read))
{
    byte[] buffer = new byte[1024];
    int bytesRead;
    while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0)
    {
        // Обрабатываем кусок данных
        Console.WriteLine($"Прочитано {bytesRead} байт");
    }
}

Запись файлов: как не потерять данные

Запись в C# — это не только File.WriteAllText. Важно понимать режимы: создать новый файл, дописать в конец или перезаписать.

Основные режимы FileMode

  • CreateNew — создаёт новый файл. Если файл существует — выбросит исключение.
  • Create — создаёт новый файл или перезаписывает существующий.
  • Append — открывает файл и дописывает в конец.
  • OpenOrCreate — открывает существующий или создаёт новый.
// Простая запись
File.WriteAllText("note.txt", "Привет, мир!");

// Дозапись в лог
File.AppendAllText("log.txt", $"{DateTime.Now}: Ошибка подключения\n");

// Запись с контролем через StreamWriter
using (StreamWriter writer = new StreamWriter("report.txt", append: true))
{
    writer.WriteLine("Новая запись в отчёте");
}

Важно про кодировки

По умолчанию StreamWriter использует UTF-8. Если работаете с кириллицей в старых системах — укажите кодировку явно:

using (StreamWriter writer = new StreamWriter("data.txt", false, Encoding.UTF8))
{
    writer.WriteLine("Текст на русском");
}

Работа с файловой системой: папки, перемещение, удаление

Файловая система — это не только файлы, но и папки. C# даёт полный контроль.

Создание и удаление папок

// Создать папку (если её нет)
Directory.CreateDirectory(@"C:\MyApp\Logs");

// Удалить папку со всем содержимым
Directory.Delete(@"C:\Temp", recursive: true);

Будьте осторожны с recursive: true — он удалит всё безвозвратно.

Копирование и перемещение

// Копирование
File.Copy("source.txt", "destination.txt", overwrite: true);

// Перемещение (работает и как переименование)
File.Move(@"C:\old\file.txt", @"C:\new\file.txt");

Совет: перед перемещением всегда проверяйте, что целевой путь не занят, иначе получите исключение.

Обход папок рекурсивно

Хотите найти все файлы .txt в папке и подпапках? Используйте Directory.EnumerateFiles — он не загружает всё в память, а выдаёт результаты по мере обхода.

IEnumerable<string> txtFiles = Directory.EnumerateFiles(
    @"C:\Documents", 
    "*.txt", 
    SearchOption.AllDirectories
);

foreach (string file in txtFiles)
{
    Console.WriteLine($"Найден: {file}");
}

Потоки (Streams): почему это важно понимать

Если вы пишете серьёзное приложение, вам придётся работать с потоками. Stream — это абстракция последовательности байтов. FileStream, MemoryStream, NetworkStream — все они наследники.

Главное правило: любой Stream

Блоги

Рекомендаций по книгам