Карта / I/O и файлы / NIO: Files и Path

NIO: Files и Path

NIO (New I/O, Java 7+) — современный способ работать с файловой системой. Старый java.io.File неудобен: нет нормальной обработки ошибок, нет поддержки символических ссылок. java.nio.file.Path и java.nio.file.Files — современная замена, которую сейчас используют в реальных проектах.

Path — путь к файлу или директории:

Path file = Path.of("src/main/resources/config.yml");   // относительный
Path abs  = Path.of("/home/user/data", "file.txt");     // абсолютный

file.getFileName()    // config.yml
file.getParent()      // src/main/resources
file.toAbsolutePath() // /home/user/project/src/...

Files — утилитный класс для всех операций:

// Читать весь файл сразу
String content = Files.readString(Path.of("note.txt"), StandardCharsets.UTF_8);
List<String> lines = Files.readAllLines(Path.of("log.txt"), StandardCharsets.UTF_8);

// Записать
Files.writeString(Path.of("out.txt"), "Hello!", StandardCharsets.UTF_8);
Files.write(Path.of("data.bin"), bytes);

// Копировать, переместить, удалить
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
Files.move(source, target);
Files.delete(path);  // бросит если не существует
Files.deleteIfExists(path);

// Проверки
Files.exists(path)
Files.isDirectory(path)
Files.size(path)      // в байтах

// Создать директории
Files.createDirectories(Path.of("a/b/c"));  // создаёт все уровни
Копнуть глубже

Обход дерева файлов. Files.walk() возвращает Stream<Path> — всё дерево файлов как стрим, можно применять фильтры:

// Найти все .java файлы в проекте
try (Stream<Path> paths = Files.walk(Path.of("src"))) {
    List<Path> javaFiles = paths
        .filter(p -> p.toString().endsWith(".java"))
        .toList();
}

Files.list(dir) — только прямые потомки директории (не рекурсивно). Files.find(start, depth, predicate) — рекурсивно с предикатом и ограничением глубины.

WatchService — отслеживать изменения файловой системы (hot reload конфигурации, мониторинг папки):

WatchService watcher = FileSystems.getDefault().newWatchService();
Path dir = Path.of("config");
dir.register(watcher, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE);

WatchKey key = watcher.take(); // блокирует до события
for (WatchEvent<?> event : key.pollEvents()) {
    System.out.println("Изменён: " + event.context());
}

Каналы (Channels) и буферы — низкоуровневое NIO. FileChannel + ByteBuffer позволяют делать memory-mapped files (файл отображается в память), zero-copy передачу (transferTo), и работать с файлом напрямую, минуя Java heap. Используется в высокопроизводительных системах (Kafka внутри активно использует FileChannel.transferTo).

🎤 Закрыл тему, если можешь объяснить:
• зачем NIO если есть java.io.File, и основные операции Files (read, write, copy, delete);
• как обойти дерево файлов через Files.walk и Stream (если дошёл до 2-го слоя).