1. Повторение: File vs Path vs Files
Старый добрый File
Да... Legacy-кода в Java-проектах хватает. Поэтому давайте ещё раз вспомним о ветеране Java, классе File. Он появился в языке ещё в первой версии и позволяет работать с файлами и папками: узнавать, существует ли файл, его имя, размер, дату изменения, создавать и удалять файлы и папки. Как мы с вами уже знаем, он полон недостатков: часть методов работает неинтуитивно, не все операции поддерживаются кроссплатформенно, а некоторые методы возвращают не исключения, а просто false (что не всегда удобно для отладки).
import java.io.File;
File file = new File("example.txt");
System.out.println("Существует ли файл? " + file.exists());
System.out.println("Это файл? " + file.isFile());
System.out.println("Это папка? " + file.isDirectory());
Path и Files: современный взгляд (Java 7+)
С выходом Java 7 появился пакет java.nio.file, который предлагает более мощные и гибкие инструменты. Два ключевых героя:
- Path — интерфейс, который описывает путь к файлу или папке. Можно сказать, что это «строка с интеллектом»: умеет разбирать, склеивать, анализировать, сравнивать пути.
- Files — утилитарный класс с кучей статических методов для работы с файлами и директориями: создание, удаление, копирование, чтение, запись, получение информации.
import java.nio.file.Path;
import java.nio.file.Paths;
Path path = Paths.get("example.txt");
System.out.println("Путь: " + path);
Забавный факт: класс Path — это не просто строка! Он знает о разделителях директорий, умеет разбирать относительные и абсолютные пути и работать одинаково хорошо на Windows и Linux.
Таблица сравнения File и Path/Files
| Критерий | File (старый API) | Path + Files (современный API) |
|---|---|---|
| Синтаксис | ООП-стиль | Комбинация Path + статические методы Files |
| Кроссплатформенность | Частичная | Отличная, учитывает ОС |
| Исключения | Не всегда | Почти всегда |
| Новые возможности | Нет | Да (атрибуты, права, ссылки и др.) |
| Рекомендуется | Скорее нет | Да |
2. Получение информации о файле/директории
Разберёмся, как узнать всё самое важное о файле или папке: существует ли объект, тип (файл или директория), размер, имя, путь и родительскую директорию.
Проверка существования
Через File
File file = new File("example.txt");
if (file.exists()) {
System.out.println("Файл существует!");
} else {
System.out.println("Файл не найден.");
}
Через Path и Files
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
Path path = Paths.get("example.txt");
if (Files.exists(path)) {
System.out.println("Файл существует!");
} else {
System.out.println("Файл не найден.");
}
Совет: Для новых проектов всегда используйте Path и Files. Это безопаснее, удобнее и кроссплатформенно.
Проверка типа: файл или директория
File
if (file.isFile()) {
System.out.println("Это файл.");
} else if (file.isDirectory()) {
System.out.println("Это папка.");
}
Path + Files
if (Files.isRegularFile(path)) {
System.out.println("Это файл.");
} else if (Files.isDirectory(path)) {
System.out.println("Это папка.");
}
Получение размера файла
File
long size = file.length();
System.out.println("Размер файла: " + size + " байт");
Path + Files
try {
long size = Files.size(path);
System.out.println("Размер файла: " + size + " байт");
} catch (IOException e) {
System.out.println("Ошибка при получении размера файла: " + e.getMessage());
}
Внимание: Для папки метод length() всегда вернёт 0, а Files.size(path) выбросит IOException. Размер папки — это сумма размеров всех файлов внутри (подробнее — в следующих лекциях).
Получение абсолютного и относительного пути
File
System.out.println("Относительный путь: " + file.getPath());
System.out.println("Абсолютный путь: " + file.getAbsolutePath());
Path
System.out.println("Относительный путь: " + path);
System.out.println("Абсолютный путь: " + path.toAbsolutePath());
Получение имени файла и родительской директории
File
System.out.println("Имя файла: " + file.getName());
System.out.println("Родительская папка: " + file.getParent());
Path
System.out.println("Имя файла: " + path.getFileName());
System.out.println("Родительская папка: " + path.getParent());
Лайфхак: Path умеет работать не только с файлами, но и с папками, относительными и абсолютными путями, а также легко разбирает путь на части.
3. Получение атрибутов файла
Иногда хочется узнать не только размер и имя файла, но и что-то более интересное: дату создания, дату последнего изменения, права доступа.
Дата создания, последнего изменения
File (ограничено)
long lastModified = file.lastModified();
System.out.println("Дата последнего изменения: " + new java.util.Date(lastModified));
Минус: Узнать дату создания файла через File невозможно!
Path + Files
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
try {
BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
FileTime creationTime = attrs.creationTime();
FileTime lastModifiedTime = attrs.lastModifiedTime();
System.out.println("Дата создания: " + creationTime);
System.out.println("Дата последнего изменения: " + lastModifiedTime);
} catch (IOException e) {
System.out.println("Ошибка при получении атрибутов: " + e.getMessage());
}
Проверка прав доступа
File
System.out.println("Можно читать? " + file.canRead());
System.out.println("Можно писать? " + file.canWrite());
System.out.println("Можно выполнять? " + file.canExecute());
Path + Files
System.out.println("Можно читать? " + Files.isReadable(path));
System.out.println("Можно писать? " + Files.isWritable(path));
System.out.println("Можно выполнять? " + Files.isExecutable(path));
Забавный факт: На Windows права доступа ограничены, а на Unix-системах можно получить и изменить гораздо больше прав (например, через POSIX-атрибуты).
4. Типичные ошибки при получении информации о файлах
Ошибка №1: Использование File, когда нужен Path.
Многие новички продолжают использовать File, потому что так проще или «так везде в интернете». Но с помощью Path и Files можно делать всё то же самое, но надёжнее и современнее.
Ошибка №2: Проверка типа объекта только через File.
Если вы используете только file.isFile() и file.isDirectory(), то можете пропустить «особые» файлы (символические ссылки, устройства). В современном API есть Files.isRegularFile(path), Files.isDirectory(path) и другие проверки.
Ошибка №3: Игнорирование исключений.
Методы Files.size(path) и Files.readAttributes(...) выбрасывают IOException. Если не обрабатывать исключения, программа рухнет при первой же ошибке доступа или если файл исчезнет во время работы.
Ошибка №4: Ожидание, что размер папки можно узнать напрямую.
Метод Files.size(path) для папки вызовет исключение. Чтобы узнать размер папки, нужно рекурсивно просуммировать размеры всех файлов внутри.
Ошибка №5: Недостаточная проверка прав доступа.
Даже если файл существует, у вас может не быть прав на его чтение или запись. Всегда проверяйте права перед операциями: Files.isReadable(path), Files.isWritable(path), Files.isExecutable(path).
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ