1. Введение
Если статические классы, такие как File и Directory, — это как универсальный швейцарский нож: всегда под рукой, быстро решают задачу, но без привязки к конкретному объекту, то FileInfo и DirectoryInfo — это уже персонализированный инструмент: он создаётся для конкретного файла или папки, «знает» о них многое и позволяет работать удобнее и гибче, особенно при множественных операциях с одним и тем же объектом.
Экземплярные классы хранят детали о конкретном объекте файловой системы, причём после первой загрузки свойств не обязательно снова лезть в файловую систему за информацией (если только объект не устарел).
- FileInfo — для работы с конкретным файлом.
- DirectoryInfo — для работы с конкретной директорией (папкой).
Они содержат свойства и методы, позволяющие получать детальную информацию (размер, дату создания, расширение, доступные атрибуты) и выполнять над файлом/папкой разные действия: копировать, удалять, перемещать и т.п.
Как устроены FileInfo и DirectoryInfo
Оба класса — наследники общего абстрактного класса FileSystemInfo, что позволяет писать код, работающий сразу с файлами и папками оптом.
System.Object
|
System.MarshalByRefObject
|
System.IO.FileSystemInfo (абстрактный класс)
| |
FileInfo DirectoryInfo
Когда использовать экземплярные классы?
- Если нужно много информации об одном файле/папке (размер, дата модификации, расширение, атрибуты и пр.), и эти данные используются не один раз.
- Если вы хотите перебрать все файлы/папки в каталоге и работать с каждым объектом как с «живым» экземпляром.
- Для оптимизации, когда важно не ходить лишний раз в файловую систему (кэширование информации).
- Для более объектно-ориентированного кода (бэкапы, медиатека, файловый менеджер и т.д.).
Как создать экземпляр FileInfo или DirectoryInfo
using System.IO;
// Создание объекта FileInfo для существующего (или несуществующего!) файла:
var fileInfo = new FileInfo("notes.txt");
// Создание объекта DirectoryInfo для папки:
var dirInfo = new DirectoryInfo(@"C:\Projects");
// Можно использовать относительные или абсолютные пути!
Важный момент: создание объекта FileInfo или DirectoryInfo НЕ создаёт файл/папку в файловой системе! Это лишь описание (связь по ссылке).
2. Работа с FileInfo
Давайте разберем основные свойства и методы этого класса. Вот памятка:
| Свойство/метод | Что возвращает? | Пример использования |
|---|---|---|
|
Имя файла | |
|
Полный путь | |
|
Размер файла в байтах | |
|
Родительский каталог (DirectoryInfo) | |
|
Есть ли файл реально? | |
|
Расширение файла (.txt) | |
|
Дата создания | |
|
Дата последнего изменения | |
|
Только для чтения? | |
| Методы | ||
|
Копировать файл | |
|
Удалить файл | |
|
Переместить файл | |
|
Открыть поток для чтения | |
|
Открыть поток для записи | |
Пример: Информация о файле
Добавим небольшой модуль, который получает подробную информацию о файле, используя FileInfo.
Console.WriteLine("Введите имя файла:");
string fileName = Console.ReadLine();
var file = new FileInfo(fileName);
if (file.Exists)
{
Console.WriteLine($"Имя файла: {file.Name}");
Console.WriteLine($"Путь: {file.FullName}");
Console.WriteLine($"Размер: {file.Length} байт");
Console.WriteLine($"Расширение: {file.Extension}");
Console.WriteLine($"Дата создания: {file.CreationTime}");
Console.WriteLine($"Последнее изменение: {file.LastWriteTime}");
// Дополнительно: показать родительскую директорию
Console.WriteLine($"Родительская папка: {file.DirectoryName}");
}
else
{
Console.WriteLine("Файл не найден.");
}
Обратите внимание: мы не читаем содержимое файла, а просто получаем метаинформацию.
Практика: Копирование и удаление файла
// ... Внутри основного метода после успешного вывода сведений о файле:
Console.WriteLine("Введите путь для копии файла:");
string copyPath = Console.ReadLine();
try
{
file.CopyTo(copyPath);
Console.WriteLine($"Файл успешно скопирован в {copyPath}");
}
catch (IOException ex)
{
Console.WriteLine($"Не удалось скопировать файл: {ex.Message}");
}
// Теперь удалим копию
Console.WriteLine("Удалить копию файла? (y/n):");
if (Console.ReadLine().Trim().ToLower() == "y")
{
var copyFile = new FileInfo(copyPath);
if (copyFile.Exists)
{
copyFile.Delete();
Console.WriteLine("Копия удалена.");
}
}
3. Работа с DirectoryInfo
Посмотрим, чем нас порадует DirectoryInfo:
| Свойство/метод | Что возвращает? | Пример использования |
|---|---|---|
|
Имя папки | |
|
Полный путь | |
|
Родительская папка (DirectoryInfo) | |
|
Папка есть? | |
|
Дата создания | |
|
Дата изменения | |
| Методы | ||
|
Создать папку | |
|
Удалить папку | |
|
Массив файлов (массив FileInfo) | |
|
Массив подпапок (массив DirectoryInfo) | |
|
Перебор файлов (возвращает IEnumerable<FileInfo>, отложенный режим) | |
|
Переместить папку | |
Пример: Перебор файлов и папок
Console.WriteLine("Введите путь к папке:");
string path = Console.ReadLine();
var dir = new DirectoryInfo(path);
if (!dir.Exists)
{
Console.WriteLine("Папка не найдена!");
return;
}
Console.WriteLine("\n--- Файлы ---");
foreach (var file in dir.GetFiles())
{
Console.WriteLine($"{file.Name} ({file.Length} байт)");
}
Console.WriteLine("\n--- Подпапки ---");
foreach (var subDir in dir.GetDirectories())
{
Console.WriteLine(subDir.Name);
}
4. Полезные нюансы
Статические методы против экземплярных классов
Когда стоит использовать какой подход? Если вы делаете быстрое «одноразовое» действие — например, File.Exists(path) или File.ReadAllText(path), — статические методы покажут себя с лучшей стороны. Они проще и чуть быстрее за счёт минимальных накладных расходов.
Если же вы хотите получить много информации о файле или папке, выполнять над этим объектом повторные операции, или просто пишете код в ООП-стиле, — лучше использовать экземпляры FileInfo и DirectoryInfo.
Интересно, что оба подхода «под капотом» используют схожие низкоуровневые системные вызовы. Но экземплярные классы кэшируют некоторые свойства (размер, дата, атрибуты), минимизируя количество обращений к файловой системе — особенно приятно при переборе большого числа файлов.
Немного о работе с датой и временем
Свойства CreationTime, LastWriteTime, LastAccessTime возвращают значения типа DateTime.
Console.WriteLine($"Файл создан: {file.CreationTime:yyyy-MM-dd HH:mm:ss}");
Console.WriteLine($"Последнее изменение: {file.LastWriteTime:yyyy-MM-dd HH:mm:ss}");
Если файл или папка была изменена на диске после того, как вы получили объект FileInfo или DirectoryInfo, кэшированная информация может устареть. Чтобы обновить её, вызовите file.Refresh().
Советы и практические замечания
- Экземплярные классы удобны, когда строите обёртку вокруг файловой системы: бэкапы, медиатека, индексатор.
- Отлично работают совместно с LINQ: можно отфильтровать по размеру, дате или расширению и выполнить операции над выбранными объектами.
- При массовых операциях предпочтительнее EnumerateFiles() и EnumerateDirectories(), чем GetFiles()/GetDirectories(), — ленивое перечисление экономит память и ускоряет старт обработки.
Сравнение статического и экземплярного подхода
| Статические методы | Экземплярные классы | |
|---|---|---|
| Синтаксис | |
|
| Кэширование | Нет | Да |
| Много информации | Нужно вызывать много методов | Есть в объекте |
| ООП-стиль | Нет | Да |
| Массовые операции | Неудобно | Удобно |
| Работа с потоками | Есть | Есть |
Обновление информации и объектов
Объекты FileInfo/DirectoryInfo кэшируют значения после первого обращения к свойствам. Если объект (файл или папка) был изменён на диске после создания экземпляра, чтобы обновить информацию, вызовите метод .Refresh().
var file = new FileInfo("notes.txt");
long oldSize = file.Length;
// В это время кто-то (или вы сами) меняет файл вне программы
file.Refresh();
long newSize = file.Length;
Это встречается нечасто, но если ваша программа наблюдает за файловой системой — механизм важен.
5. Типичные ошибки при работе с экземплярными классами
Заблуждение: если создан объект new FileInfo("file.txt"), то файл уже существует. На самом деле, это не так — файл появляется только после явной записи или вызова Create().
Попытка получить свойства файла, который не существует: некоторые свойства вернут значения по умолчанию (например, размер 0), но попытка открыть поток чтения вызовет исключение.
С папками аналогично: создание DirectoryInfo не гарантирует, что папка есть на диске до вызова Create() или её фактического появления.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ