1. Создание директорий
Директория (она же папка) — это не просто контейнер для файлов, а основа организации данных на диске. В приложениях мы постоянно создаём каталоги для входных/выходных данных, логов, временных файлов и т.д. Современный API java.nio.file делает это удобно и кроссплатформенно.
Давайте посмотрим, как создавать, удалять и просматривать содержимое папок с помощью классов Files, Path и Paths.
Files.createDirectory(path)
Создаёт одну директорию по указанному пути. Если родительская директория отсутствует — будет выброшено исключение.
import java.nio.file.*;
public class DirectoryDemo {
public static void main(String[] args) throws Exception {
Path dir = Paths.get("testDir");
if (!Files.exists(dir)) {
Files.createDirectory(dir);
System.out.println("Директория создана: " + dir.toAbsolutePath());
} else {
System.out.println("Директория уже существует: " + dir.toAbsolutePath());
}
}
}
Если вы попробуете создать директорию, которая уже есть, получите FileAlreadyExistsException.
Files.createDirectories(path)
Создаёт всю цепочку директорий. Если какой-то из промежуточных каталогов отсутствует — он будет создан автоматически. Если часть цепочки уже существует — ошибки не будет.
Path nestedDir = Paths.get("parent/child/grandchild");
Files.createDirectories(nestedDir);
System.out.println("Создана цепочка директорий: " + nestedDir.toAbsolutePath());
Это как если бы вы попросили Java построить не только дом, но и подъезд, и улицу, если их ещё не было.
Типичный пример: создаём структуру для проекта
Допустим, нужно сохранять отчёты в папку output/reports/2024. Не проверяйте каждую директорию вручную — используйте createDirectories.
Path reportsPath = Paths.get("output/reports/2024");
Files.createDirectories(reportsPath);
Java сама разберётся, что уже есть, а что нужно создать.
2. Удаление файлов и директорий
Files.delete(path)
Удаляет файл или пустую директорию. Если директория не пуста — будет выброшено DirectoryNotEmptyException.
Path dir = Paths.get("testDir");
try {
Files.delete(dir);
System.out.println("Директория удалена: " + dir.toAbsolutePath());
} catch (DirectoryNotEmptyException e) {
System.out.println("Невозможно удалить: директория не пуста!");
}
Files.deleteIfExists(path)
Работает как delete, но не выбрасывает ошибку, если объекта нет. Возвращает true, если что-то было удалено, и false — если объекта не было.
Path file = Paths.get("output/reports/2024/report.txt");
if (Files.deleteIfExists(file)) {
System.out.println("Файл удалён.");
} else {
System.out.println("Файл не найден, ничего не удалено.");
}
Как удалить непустую директорию?
Непустую папку просто так удалить нельзя. Сначала нужно удалить всё её содержимое (файлы и поддиректории), а затем саму папку. Делается это рекурсивно, например, через Files.walkFileTree:
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
public class DeleteDirectoryRecursively {
public static void main(String[] args) throws IOException {
Path dir = Paths.get("parent");
if (Files.exists(dir)) {
Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
System.out.println("Директория и все её содержимое удалены.");
}
}
}
Если вы только начинаете, не пугайтесь этого кода — позже разберём walkFileTree подробнее.
3. Просмотр содержимого директории
Files.list(path)
Возвращает Stream<Path> — поток путей. Вы можете обрабатывать содержимое папки через Stream API. Каждая запись — файл или поддиректория (без рекурсии!).
Path dir = Paths.get("output/reports");
if (Files.exists(dir) && Files.isDirectory(dir)) {
try (var stream = Files.list(dir)) {
stream.forEach(path -> System.out.println(path.getFileName()));
}
}
Важная деталь: поток обязательно нужно закрывать, поэтому используем try‑with‑resources.
Пример: выводим имена файлов и поддиректорий
Path reports2024 = Paths.get("output/reports/2024");
try (var stream = Files.list(reports2024)) {
stream.forEach(path -> {
String type = Files.isDirectory(path) ? "директория" : "файл";
System.out.println(path.getFileName() + " — " + type);
});
}
Получение списка файлов в виде коллекции
List<Path> files = Files.list(reports2024)
.filter(Files::isRegularFile)
.toList();
System.out.println("Файлы в папке:");
files.forEach(System.out::println);
Важно: Files.list(path) возвращает только содержимое текущей директории (верхний уровень). Для рекурсивного обхода используйте Files.walk(path).
4. Практика: мини‑файловый менеджер
Утилита создаёт директорию mydata/logs, файл log1.txt, выводит содержимое папки и затем всё удаляет.
import java.nio.file.*;
import java.io.IOException;
public class MiniFileManager {
public static void main(String[] args) throws IOException {
Path logsDir = Paths.get("mydata/logs");
Files.createDirectories(logsDir);
Path logFile = logsDir.resolve("log1.txt");
Files.writeString(logFile, "Привет, лог!");
System.out.println("Содержимое папки " + logsDir + ":");
try (var stream = Files.list(logsDir)) {
stream.forEach(path -> System.out.println(" - " + path.getFileName()));
}
Files.deleteIfExists(logFile);
Files.deleteIfExists(logsDir);
System.out.println("Файл и папка удалены.");
}
}
Комментарии к коду:
- Files.createDirectories гарантирует создание всей цепочки.
- resolve — удобный способ добавить к пути имя файла.
- Закрываем поток от Files.list через try‑with‑resources — особенно критично в Windows.
5. Особенности и нюансы
Проверка существования
Перед созданием/удалением полезно проверить, существует ли путь:
if (!Files.exists(path)) {
Files.createDirectory(path);
}
Права доступа
Если у программы нет прав на создание/удаление — получите AccessDeniedException. Например, создание папки в корне диска от обычного пользователя почти всегда закончится ошибкой.
Пустая и непустая директория
Удалить можно только пустую директорию (Files.delete). Для удаления со всем содержимым используйте рекурсивный обход (walkFileTree).
Кроссплатформенность
API java.nio.file корректно работает на всех популярных ОС и учитывает разделители путей. Для построения путей используйте Paths.get и Path.resolve, а не склеивайте строки.
Символические ссылки
В базовых задачах о них можно не думать, но если встретите «необычные» записи, которые не являются ни обычным файлом, ни директорией — возможно, это симлинки. К ним вернёмся в продвинутых лекциях.
6. Типичные ошибки при работе с директориями
Ошибка №1: попытка удалить непустую директорию простым вызовом Files.delete(path). Java выбросит DirectoryNotEmptyException. Сначала удалите содержимое, затем саму папку.
Ошибка №2: забыли закрыть поток из Files.list(). Если не использовать try‑with‑resources, поток останется открытым, и на Windows возможна ошибка при удалении папки.
Ошибка №3: создание директории без проверки наличия родителя. Вызов Files.createDirectory для пути вида parent/child, когда parent не существует, приведёт к NoSuchFileException. Используйте Files.createDirectories.
Ошибка №4: использование абсолютных путей без необходимости. Предпочитайте относительные пути внутри проекта — так код будет переносимее.
Ошибка №5: не обрабатывается IOException. Любая операция с ФС может завершиться ошибкой. Оборачивайте в try-catch или пробрасывайте исключение выше.
Ошибка №6: попытка создать/удалить в папке, к которой нет прав. В этом случае получите AccessDeniedException. Проверьте контекст запуска и права доступа.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ