Path и Files
Современный API находится в пакете java.nio.file. Класс Path описывает путь, класс Files выполняет операции.
import java.nio.file.Path;public class PathDemo { public static void main(String[] args) { Path path = Path.of("data", "notes", "todo.txt"); System.out.println(path); System.out.println(path.getFileName()); System.out.println(path.getParent()); System.out.println(path.isAbsolute()); System.out.println(path.toAbsolutePath()); System.out.println(path.resolveSibling("done.txt")); System.out.println(Path.of("data").resolve("a.txt")); }}Разделитель путей зависит от системы, поэтому собирайте пути через Path.of(...) и resolve.
Чтение текстового файла
import java.io.IOException;import java.nio.charset.StandardCharsets;import java.nio.file.Files;import java.nio.file.Path;import java.util.List;public class ReadText { public static void main(String[] args) throws IOException { Path file = Path.of("notes.txt"); String all = Files.readString(file, StandardCharsets.UTF_8); System.out.println(all); List<String> lines = Files.readAllLines(file); for (String line : lines) { System.out.println(line); } }}Для больших файлов читайте построчно потоком:
import java.io.IOException;import java.nio.file.Files;import java.nio.file.Path;import java.util.stream.Stream;public class ReadLines { public static void main(String[] args) throws IOException { try (Stream<String> lines = Files.lines(Path.of("big.txt"))) { long count = lines.filter(l -> l.contains("ERROR")).count(); System.out.println(count); } }}Поток Files.lines нужно закрывать, поэтому используется try-with-resources.
Запись текстового файла
import java.io.IOException;import java.nio.file.Files;import java.nio.file.Path;import java.nio.file.StandardOpenOption;import java.util.List;public class WriteText { public static void main(String[] args) throws IOException { Path file = Path.of("output.txt"); Files.writeString(file, "Первая строка\n"); Files.writeString(file, "Вторая строка\n", StandardOpenOption.APPEND); Files.write(file, List.of("Третья", "Четвертая"), StandardOpenOption.APPEND); System.out.println(Files.readString(file)); }}По умолчанию файл создается или перезаписывается. Для дописывания используйте StandardOpenOption.APPEND.
Буферизованные чтение и запись
import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.IOException;import java.nio.file.Files;import java.nio.file.Path;public class Buffered { public static void main(String[] args) throws IOException { Path file = Path.of("buffered.txt"); try (BufferedWriter writer = Files.newBufferedWriter(file)) { for (int i = 1; i <= 3; i++) { writer.write("Строка " + i); writer.newLine(); } } try (BufferedReader reader = Files.newBufferedReader(file)) { String line; while ((line = reader.readLine()) != null) { System.out.println(line); } } }}Работа с файлами и каталогами
import java.io.IOException;import java.nio.file.Files;import java.nio.file.Path;import java.nio.file.StandardCopyOption;public class FileOps { public static void main(String[] args) throws IOException { Path dir = Path.of("workspace", "reports"); Files.createDirectories(dir); Path file = dir.resolve("report.txt"); if (!Files.exists(file)) { Files.createFile(file); } Files.writeString(file, "данные"); System.out.println(Files.size(file)); System.out.println(Files.isDirectory(dir)); System.out.println(Files.isRegularFile(file)); Path copy = dir.resolve("copy.txt"); Files.copy(file, copy, StandardCopyOption.REPLACE_EXISTING); Path moved = dir.resolve("moved.txt"); Files.move(copy, moved, StandardCopyOption.REPLACE_EXISTING); Files.delete(moved); Files.deleteIfExists(file); }}Список и обход каталога
import java.io.IOException;import java.nio.file.Files;import java.nio.file.Path;import java.util.stream.Stream;public class ListDir { public static void main(String[] args) throws IOException { try (Stream<Path> entries = Files.list(Path.of("."))) { entries.forEach(p -> System.out.println(p.getFileName())); } try (Stream<Path> tree = Files.walk(Path.of("."), 3)) { tree.filter(Files::isRegularFile) .filter(p -> p.toString().endsWith(".java")) .forEach(System.out::println); } }}Files.list показывает один уровень, Files.walk обходит вложенные каталоги.
Рекурсивное удаление каталога
import java.io.IOException;import java.nio.file.Files;import java.nio.file.Path;import java.util.Comparator;import java.util.stream.Stream;public class DeleteTree { static void deleteRecursively(Path root) throws IOException { try (Stream<Path> tree = Files.walk(root)) { tree.sorted(Comparator.reverseOrder()).forEach(p -> { try { Files.delete(p); } catch (IOException e) { throw new RuntimeException(e); } }); } } public static void main(String[] args) throws IOException { deleteRecursively(Path.of("workspace")); }}Сортировка в обратном порядке гарантирует, что вложенные элементы удаляются раньше родительских каталогов.
Двоичные данные
import java.io.IOException;import java.nio.file.Files;import java.nio.file.Path;import java.util.Arrays;public class Binary { public static void main(String[] args) throws IOException { Path file = Path.of("data.bin"); byte[] bytes = {1, 2, 3, (byte) 255}; Files.write(file, bytes); byte[] read = Files.readAllBytes(file); System.out.println(Arrays.toString(read)); }}Для потокового чтения используйте InputStream и OutputStream:
import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.nio.file.Files;import java.nio.file.Path;public class CopyStreams { public static void main(String[] args) throws IOException { try (InputStream in = Files.newInputStream(Path.of("source.bin")); OutputStream out = Files.newOutputStream(Path.of("target.bin"))) { in.transferTo(out); } }}Кодировки
Всегда указывайте кодировку явно, если работаете с текстом в разных системах:
String text = Files.readString(Path.of("a.txt"), StandardCharsets.UTF_8);Files.writeString(Path.of("b.txt"), text, StandardCharsets.UTF_8);С Java 18 UTF-8 используется по умолчанию, но явное указание не мешает.
Properties
Простой формат конфигурации ключ=значение:
import java.io.IOException;import java.io.Reader;import java.io.Writer;import java.nio.file.Files;import java.nio.file.Path;import java.util.Properties;public class PropertiesDemo { public static void main(String[] args) throws IOException { Path file = Path.of("app.properties"); Properties out = new Properties(); out.setProperty("host", "localhost"); out.setProperty("port", "8080"); try (Writer writer = Files.newBufferedWriter(file)) { out.store(writer, "Настройки"); } Properties in = new Properties(); try (Reader reader = Files.newBufferedReader(file)) { in.load(reader); } System.out.println(in.getProperty("host")); System.out.println(Integer.parseInt(in.getProperty("port", "80"))); }}Сериализация объектов
Интерфейс-маркер Serializable разрешает записывать объект в поток байтов:
import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable;import java.nio.file.Files;import java.nio.file.Path;public class SerializationDemo { static class Profile implements Serializable { private static final long serialVersionUID = 1L; String name; int level; transient String password; Profile(String name, int level, String password) { this.name = name; this.level = level; this.password = password; } } public static void main(String[] args) throws IOException, ClassNotFoundException { Path file = Path.of("profile.ser"); try (ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(file))) { out.writeObject(new Profile("Анна", 7, "secret")); } try (ObjectInputStream in = new ObjectInputStream(Files.newInputStream(file))) { Profile p = (Profile) in.readObject(); System.out.println(p.name + " " + p.level + " " + p.password); } }}Поле transient не сериализуется, поэтому password после чтения равен null. Не десериализуйте данные из недоверенных источников: это известный вектор атак. Для обмена данными предпочитайте JSON.
Устаревший класс File
В старом коде встречается java.io.File. Его можно преобразовать в современный API:
import java.io.File;import java.nio.file.Path;public class Legacy { public static void main(String[] args) { File file = new File("notes.txt"); Path path = file.toPath(); File back = path.toFile(); System.out.println(file.exists() + " " + back.getName()); }}