JavaRush /Курсы /C# SELF /Режимы открытия файлов

Режимы открытия файлов

C# SELF
35 уровень , 4 лекция
Открыта

1. Введение

Когда вы работаете с файлами через FileStream или другие потоковые классы, очень важно заранее понять, что именно произойдет с файлом при попытке его открыть. Часто возникает ситуация, когда файл уже существует, и вы хотите либо добавить новые данные, не потеряв старые, либо перезаписать файл полностью. С другой стороны, бывают моменты, когда файл ещё не создан, и вы хотите его прочитать, не рискуя случайно создать пустой файл.

Например, если вы пишете блокнот для ежедневных заметок, ваша задача — добавлять новые записи в конец уже существующего файла, сохраняя всё, что было написано раньше. Это значит, что вам нужно открыть файл в режиме добавления. В другом случае — скажем, у вас есть лог-файл, который должен каждый раз создаваться заново при запуске приложения, чтобы не мешать старым данным. Здесь нужно открыть файл так, чтобы при открытии он очищался или создавался заново, если не существует. А если ваша задача просто прочитать существующий файл, вы, скорее всего, захотите убедиться, что не создадите новый файл, если его нет, иначе можете получить пустой файл там, где его быть не должно.

Все эти различные ситуации — добавление, перезапись, чтение без создания — реализуются в C# через специальные режимы открытия файлов, которые задаются с помощью перечисления System.IO.FileMode. Каждый режим управляет поведением при открытии или создании файла, помогая вам точно контролировать, что происходит с файлом при взаимодействии с ним.

2. Перечисление FileMode — все варианты на пальцах

Вот основные значения перечисления FileMode:

Значение Описание Поведение при существующем файле Поведение при отсутствии файла
CreateNew
Создает новый файл. Если файл уже существует — бросает исключение Ошибка Ок, файл создан
Create
Создаёт новый файл если его нет, или перезаписывает существующий Перезаписывает Ок, создает
Open
Открывает существующий файл. Если файла нет — исключение Ок, открывает Ошибка
OpenOrCreate
Откроет если есть, а если нет — создаст новый Ок, открывает Ок, создает
Truncate
Открывает существующий файл и обнуляет его длину (содержимое удаляется) Ок, очищает файл Ошибка
Append
Открывает файл для дозаписи в конец, если нет — создает новый Ок, добавляет в конец Ок, создает

Иллюстрация: Сценарии поведения

flowchart TD
    Start[Начало]
    A{Файл существует?}
    B1[Открыть для дозаписи]
    B2[Создать новый файл]
    B3[Перезаписать файл]
    B4[Открыть файл]
    B5[Ошибка: файл не найден]
    B6[Ошибка: файл уже существует]

    Start --> A
    A --Append, OpenOrCreate--> B1
    A --Create, Truncate--> B3
    A --Open, Truncate--> B4
    A --CreateNew--> B6
    A --Create, OpenOrCreate, Append--> B2
    A --Open, Truncate--> B5
    
Сценарии поведения для разных режимов FileMode

3. Примеры открытия файлов в разных режимах

Давайте попробуем всё это на практике с нашим мини-приложением, которое мы развиваем на протяжении курса. Пусть у нас есть текстовый файл, куда мы пишем приветствия и дату обращения. Мы рассмотрим три типовых сценария:

  • А. Создаём новый файл (CreateNew)
  • Б. Перезаписываем файл (Create)
  • В. Добавляем строки в конец файла (Append)

Создание нового файла (FileMode.CreateNew)

Если файл уже существует, этот режим гарантирует, что создать его заново не получится: программа выбросит исключение IOException. Это подойдёт, если нельзя потерять данные или случайно стереть чужие файлы.

using System;
using System.IO;

string filePath = "greeting.txt";

// Попытаемся создать новый файл — если он уже есть, будет исключение!
try
{
    var stream = new FileStream(filePath, FileMode.CreateNew, FileAccess.Write);
    var writer = new StreamWriter(stream);
    
    writer.WriteLine("Привет! Это первая запись.");
    writer.WriteLine($"Дата: {DateTime.Now}");
    
    Console.WriteLine("Файл успешно создан.");   
    writer.Close();
}
catch (IOException)
{
    Console.WriteLine($"Файл '{filePath}' уже существует! Не будем его перезаписывать.");
}

Обратите внимание: если вы запускаете этот код второй раз — catch сработает, данные не будут затёрты.

Перезапись файла (FileMode.Create)

Этот режим совсем не церемонится: если файл уже есть, он будет полностью очищен. Если нет — просто будет создан новый. Удобно, когда нужно каждый раз начинать "с чистого листа". Например, пересохранять отчёт.

using System;
using System.IO;

string filePath = "greeting.txt";

// Создание или полная перезапись файла
var stream = new FileStream(filePath, FileMode.Create, FileAccess.Write);
var writer = new StreamWriter(stream);

writer.WriteLine("Привет! Я полностью обновил файл :)");
writer.WriteLine($"Обновлено: {DateTime.Now}");

Console.WriteLine("Файл создан или перезаписан.");
writer.Close();

Запустите этот код несколько раз — в файле всегда будет только последние добавленные строки. Всё старое исчезает без следа.

Дозапись в конец файла (FileMode.Append)

Замечательный режим для логов, журналов событий, учёта посещений и т.д. Если файла нет — он создаётся. Если есть — данные добавляются в конец.

using System;
using System.IO;

string filePath = "greeting.txt";

// Добавление новой строки в конец файла
var stream = new FileStream(filePath, FileMode.Append, FileAccess.Write);
var writer = new StreamWriter(stream);

writer.WriteLine($"Ещё одно приветствие! Дата: {DateTime.Now}");

Console.WriteLine("Добавили новую строку в конец файла.");
writer.Close();

Попробуйте запускать этот код много раз подряд. Файл будет расти, каждая новая запись окажется в самом конце.

4. Как выбрать режим открытия файла? Практические советы

Сценарии из реальной жизни:

  • Логирование: почти всегда используйте Append. Сбросить логи из-за перезаписи — боль администратора и подарок злодею.
  • Экспорт отчёта: чаще используется Create, чтобы не захламлять папку старыми версиями.
  • Выгрузка данных, критичных к потере: тут подходит CreateNew. Если файл есть — ошибка, ничего не трогаем.
  • Чтение файла: тут вообще не нужен режим создания, используйте FileMode.Open — если файла нет, это сигнализирует о проблеме.

При написании кода на C# часто используются статические методы класса File, которые внутри сами выбирают подходящий режим. Например, File.AppendAllText всегда работает через Append, а File.WriteAllText — через Create.

5. Файловые режимы и проблемы при работе

Немного коварных моментов:

Если вы открываете файл с режимом FileMode.Create или FileMode.Truncate, все содержимое будет уничтожено. Будьте осторожны — случайной потерей данных страдали не только студенты, но и заслуженные программисты с огромным опытом.

Если пытаетесь открыть несуществующий файл с помощью FileMode.Open или FileMode.Truncate, получите FileNotFoundException. Не забывайте проверять, что файл действительно есть с помощью File.Exists(path).

С режимом Append можно только писать. Если вам нужно и читать, и писать, рассмотрите другие режимы (OpenOrCreate + соответствующий FileAccess).

Пример: Чтение и запись

Иногда хочется и читать, и писать в файл (например, открыли банковский счёт — хотите и внести деньги, и проверить баланс). Используйте FileMode.OpenOrCreate:

using System.IO;

string filePath = "balance.txt";

// Открытие файла для чтения и записи; если нет — создать
var stream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
// Тут можно и читать, и писать

6. Полезные нюансы

Режимы открытия файла

        graph TD
        A[Запросить файл] --> B[Выбрать режим]
        B --> C1[CreateNew] -->|Если файл есть| D1[Ошибка]
        C1 -->|Файл не существует| E1[Создать]
        B --> C2[Create] -->|Всегда| F1[Создать/Перезаписать]
        B --> C3[Open] -->|Файл есть| G1[Открыть]
        C3 -->|Файла нет| D1
        B --> C4[OpenOrCreate] -->|Файл есть| G1
        C4 -->|Файла нет| E1
        B --> C5[Append] -->|Файл есть| H1[Открыть для дозаписи]
        C5 -->|Файла нет| E1
        B --> C6[Truncate] -->|Файл есть| I1[Очищаем]
        C6 -->|Файла нет| D1
    
Схема принятия решения по режиму открытия файла

Сводная таблица по режимам открытия

FileMode Файл Существует Файл НЕ существует Доступ к данным Удаляет старое содержимое?
CreateNew
Исключение Создаёт новый Пишет Н/Д
Create
Перезаписывает Создаёт новый Пишет Да
Open
Открывает Исключение Читает/пишет Нет
OpenOrCreate
Открывает Создаёт новый Читает/пишет Нет
Truncate
Очищает Исключение Пишет Да
Append
Открывает для записи в конец Создаёт новый Только пишет Нет (добавляет)

Сравнение с высокоуровневыми методами класса File

  • File.WriteAllText(path, text) → внутри использует FileMode.Create, то есть старый файл перезапишется.
  • File.AppendAllText(path, text) → используется режим Append, все допишется в конец.
  • File.ReadAllText(path) → открывает файл на чтение (FileMode.Open).

Иногда достаточно этих методов, но работа с FileStream и явным указанием режима даёт полный контроль над происходящим.

Особенности для разных операционных систем

Часто разработчики не учитывают, что в Windows файл, который открыт другим процессом для записи, может быть недоступен для повторного открытия — попытка доступа приведёт к ошибке. Поэтому очень важно правильно использовать параметр FileShare, чтобы управлять совместным доступом к файлу (об этом мы подробнее поговорим в одной из следующих лекций). В разных операционных системах механизмы блокировок и разрешений могут отличаться, однако сама концепция режимов открытия файлов остаётся универсальной.

2
Задача
C# SELF, 35 уровень, 4 лекция
Недоступна
Дозапись в конец файла
Дозапись в конец файла
1
Опрос
Работа с файлами, 35 уровень, 4 лекция
Недоступен
Работа с файлами
Основы работы с файлами в C#
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ