Урок 8.9 — Работа с файлами
Чтение и запись файлов, работа с путями, StreamReader и StreamWriter.
Почти любая программа работает с файлами: читает конфигурацию, сохраняет результаты, логирует события, обрабатывает данные. C# предоставляет богатый набор классов в пространстве имён System.IO для работы с файловой системой. В этом уроке мы научимся читать, писать, проверять существование файлов и правильно обрабатывать ошибки.
Классы File и FileInfo
В .NET есть два основных класса для работы с файлами: File (статические методы) и FileInfo (экземплярный класс с методами для конкретного файла). Оба находятся в пространстве имён System.IO.
Класс File содержит только статические методы. Удобен для быстрых операций, не требует создания экземпляра. Хорош для небольших файлов (читает целиком в память).
using System.IO;
// Чтение
string text = File.ReadAllText("file.txt");
string[] lines = File.ReadAllLines("file.txt");
byte[] bytes = File.ReadAllBytes("file.bin");
// Запись
File.WriteAllText("file.txt", "Hello, World!");
File.WriteAllLines("file.txt", new[] { "line1", "line2" });
File.WriteAllBytes("file.bin", new byte[] { 1, 2, 3 });
// Проверка
bool exists = File.Exists("file.txt");
FileInfo info = new FileInfo("file.txt"); // FileInfo — экземплярный класс
// Копирование, перемещение, удаление
File.Copy("source.txt", "dest.txt", overwrite: true);
File.Move("source.txt", "newFolder/source.txt");
File.Delete("obsolete.txt");
FileInfo предоставляет доступ к свойствам файла (размер, дата создания и т.д.) и методы для операций. Полезен, когда нужно многократно обращаться к одному файлу.
var fileInfo = new FileInfo("document.txt");
// Свойства
Console.WriteLine($"Имя: {fileInfo.Name}");
Console.WriteLine($"Полный путь: {fileInfo.FullName}");
Console.WriteLine($"Размер: {fileInfo.Length} байт");
Console.WriteLine($"Расширение: {fileInfo.Extension}");
Console.WriteLine($"Существует: {fileInfo.Exists}");
Console.WriteLine($"Создан: {fileInfo.CreationTime}");
Console.WriteLine($"Изменён: {fileInfo.LastWriteTime}");
// Методы
if (fileInfo.Exists)
{
fileInfo.CopyTo("backup.txt");
fileInfo.MoveTo("archive/document.txt");
fileInfo.Delete();
}
// Свойства Directory
Console.WriteLine($"Папка: {fileInfo.DirectoryName}");
var dir = fileInfo.Directory;
Console.WriteLine($"Файлов в папке: {dir.GetFiles().Length}");
Пространство имён System.IO: File, Directory, Path
Пространство имён System.IO содержит основные классы для ввода-вывода. Помимо File и FileInfo, важны Directory (работа с папками) и Path (работа с путями).
Directory — работа с каталогами
// Создание, удаление, проверка
Directory.CreateDirectory(@"C:\MyApp\Data");
bool dirExists = Directory.Exists(@"C:\MyApp\Data");
Directory.Delete(@"C:\MyApp\Data", recursive: true);
// Получение файлов и подпапок
string[] files = Directory.GetFiles(@"C:\MyApp", "*.txt");
string[] dirs = Directory.GetDirectories(@"C:\MyApp");
string[] all = Directory.GetFileSystemEntries(@"C:\MyApp");
// Текущая директория
string current = Directory.GetCurrentDirectory();
Path — работа с путями
// Комбинирование путей (правильные разделители!)
string fullPath = Path.Combine(@"C:\MyApp", "Data", "file.txt");
// → C:\MyApp\Data\file.txt
string ext = Path.GetExtension("document.txt"); // → .txt
string name = Path.GetFileNameWithoutExtension("document.txt"); // → document
string dir = Path.GetDirectoryName(@"C:\MyApp\Data\file.txt"); // → C:\MyApp\Data
string fileName = Path.GetFileName(@"C:\MyApp\Data\file.txt"); // → file.txt
// Временные файлы
string tempFile = Path.GetTempFileName();
string tempDir = Path.GetTempPath();
// Случайное имя файла
string random = Path.GetRandomFileName();
Чтение файлов: ReadAllText, ReadAllLines, StreamReader
В C# есть несколько способов чтения файлов. Выбор зависит от размера файла и формата данных. File.ReadAllText() и File.ReadAllLines() читают файл целиком — подходят для небольших файлов. StreamReader читает построчно — подходит для больших файлов.
// Способ 1: File.ReadAllText() — весь файл одной строкой
string content = File.ReadAllText("data.txt");
Console.WriteLine(content);
// Способ 2: File.ReadAllLines() — массив строк
string[] lines = File.ReadAllLines("data.txt");
foreach (string line in lines)
{
Console.WriteLine($"Строка: {line}");
}
// Способ 3: File.ReadAllLines() + LINQ
var longLines = File.ReadAllLines("data.txt")
.Where(line => line.Length > 50)
.ToList();
// Способ 4: StreamReader — чтение построчно (для больших файлов)
using var reader = new StreamReader("bigfile.txt");
string? line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
// Dispose() освободит файл автоматически
// Способ 5: StreamReader — всё сразу
using var reader2 = new StreamReader("data.txt");
string allText = reader2.ReadToEnd();
StreamReader — он не загружает весь файл в память. File.ReadAllText() читает всё сразу — для файлов больше 100 МБ это может вызвать проблемы с памятью.Запись файлов: WriteAllText, WriteAllLines, StreamWriter
Для записи файлов есть симметричные методы. File.WriteAllText() и File.WriteAllLines() — для небольших объёмов. StreamWriter — для построчной записи или больших объёмов.
// Способ 1: File.WriteAllText() — записать строку
File.WriteAllText("output.txt", "Hello, World!");
// Способ 2: File.WriteAllLines() — записать массив строк
string[] data = { "Строка 1", "Строка 2", "Строка 3" };
File.WriteAllLines("output.txt", data);
// Способ 3: File.AppendAllText() — дописать в конец (без перезаписи)
File.AppendAllText("log.txt", $"{DateTime.Now}: действие выполнено\n");
// Способ 4: StreamWriter — построчная запись
using var writer = new StreamWriter("output.txt");
writer.WriteLine("Первая строка");
writer.WriteLine("Вторая строка");
writer.Write("Третья ");
writer.Write("строка (без переноса)");
// Способ 5: StreamWriter с указанием кодировки
using var writer2 = new StreamWriter("utf8.txt", append: true,
encoding: System.Text.Encoding.UTF8);
writer2.WriteLine("Текст в UTF-8");
File.WriteAllText() использует UTF-8 без BOM. Если нужно дописать в существующий файл, используй File.AppendAllText().Блок using для работы с файлами
File.ReadAllText() и File.WriteAllText() автоматически открывают и закрывают файл. Но при использовании StreamReader / StreamWriter нужно явно освобождать ресурсы. Всегда используй using!
// ❌ ПЛОХО: файл может не закрыться
static void BadExample()
{
var reader = new StreamReader("data.txt");
string data = reader.ReadToEnd();
// если исключение — файл останется открытым!
}
// ✅ ХОРОШО: using гарантирует закрытие
static void GoodExample()
{
using var reader = new StreamReader("data.txt");
string data = reader.ReadToEnd();
// reader.Dispose() будет вызван при выходе из метода
}
// ✅ Чтение и запись с using
static void CopyFile(string source, string dest)
{
using var reader = new StreamReader(source);
using var writer = new StreamWriter(dest);
string? line;
while ((line = reader.ReadLine()) != null)
{
writer.WriteLine(line.ToUpper());
}
}
File.Exists(), Path.Combine(), Path.GetExtension()
Три метода, которые ты будешь использовать постоянно при работе с файлами:
Проверяет, существует ли файл. Возвращает bool. Всегда проверяй перед чтением!
if (File.Exists("config.json"))
{
string config = File.ReadAllText("config.json");
}
else
{
Console.WriteLine("Файл не найден!");
}
Соединяет части пути с правильным разделителем для ОС. Никогда не склеивай пути через +!
string baseDir = @"C:\Users\Анна\Documents";
string file = Path.Combine(baseDir, "Projects", "data.txt");
// → C:\Users\Анна\Documents\Projects\data.txt
Извлекает расширение файла (с точкой). Полезно для проверки типа файла.
string file = "report.pdf";
string ext = Path.GetExtension(file); // → ".pdf"
if (ext == ".txt" || ext == ".csv")
{
// обрабатываем текстовый файл
}
Обработка исключений: FileNotFoundException, IOException
Работа с файлами — одна из самых «рискованных» операций. Файл может отсутствовать, быть занятым другим процессом, диск может быть переполнен. Всегда обрабатывай исключения!
static string ReadFileSafe(string filePath)
{
try
{
if (!File.Exists(filePath))
throw new FileNotFoundException($"Файл не найден: {filePath}");
return File.ReadAllText(filePath);
}
catch (FileNotFoundException ex)
{
Console.WriteLine($"Ошибка: {ex.Message}");
return string.Empty;
}
catch (UnauthorizedAccessException)
{
Console.WriteLine("Нет прав на чтение файла");
return string.Empty;
}
catch (IOException ex) when (ex is not FileNotFoundException)
{
// IOException — родитель для многих файловых исключений
Console.WriteLine($"Ошибка ввода-вывода: {ex.Message}");
return string.Empty;
}
catch (Exception ex)
{
Console.WriteLine($"Неожиданная ошибка: {ex.Message}");
return string.Empty;
}
}
Основные файловые исключения:
FileNotFoundException— файл не найден.DirectoryNotFoundException— каталог не найден.UnauthorizedAccessException— нет прав доступа.IOException— общая ошибка ввода-вывода (диск полон, файл занят).PathTooLongException— слишком длинный путь.DriveNotFoundException— диск не найден.
Мини-тест
Вопрос 1: Какой класс использовать для чтения больших файлов построчно?
Правильный ответ: B
Вопрос 2: Как правильно склеить части пути в C#?
Правильный ответ: C
Вопрос 3: Какое исключение выбрасывается, если файл не найден?
Правильный ответ: B
Вопрос 4: Как получить расширение файла "image.png"?
Правильный ответ: A
Вопрос 5: Что вернёт File.Exists() для несуществующего файла?
Правильный ответ: B
Задание
Анализатор текстовых файлов
Создай консольную программу для анализа текстовых файлов:
- Запроси у пользователя путь к файлу.
- Проверь существование файла (File.Exists). Если нет — сообщи об ошибке.
- Прочитай файл с помощью StreamReader (с использованием using).
- Подсчитай: количество строк, количество слов (разделитель — пробел), количество символов.
- Найди самую длинную строку и самый часто встречающийся символ (без учёта регистра).
- Запиши результаты анализа в новый файл с помощью StreamWriter.
- Добавь обработку исключений (FileNotFoundException, IOException, UnauthorizedAccessException).
- Используй Path.Combine для создания пути к файлу результата.
Цель
Отработать чтение, запись, Path.Combine, File.Exists, исключения и using.
Сложность
Средняя
Что важно запомнить
File.ReadAllText() (весь файл строкой), File.ReadAllLines() (массив строк), StreamReader (построчно для больших файлов).File.WriteAllText(), File.WriteAllLines(), StreamWriter, File.AppendAllText() для дописывания.Тест: 8.9: Работа с файлами
3 вопроса