Файлы в Java: от новичка до профи за 20 минут

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Почему работа с файлами в Java — это не страшно?

Каждый разработчик, даже если он пишет только бэкенд на Java, рано или поздно сталкивается с необходимостью сохранить данные, прочитать конфигурацию или обработать лог. Работа с файлами и файловой системой в Java — это базовый навык, который превращает «игрушечные» консольные приложения в настоящие утилиты. И да, в 2024 году у нас есть не только старый добрый File, но и мощный java.nio.file.

В этой статье мы разберём всё: от открытия блокнота до манипуляции с правами доступа. Поехали!

1. Классический подход: java.io.File

Начнём с дедушки. Класс File появился в Java 1.0 и до сих пор используется. Но будьте честны: он больше про метаданные, чем про содержимое. С его помощью можно проверить, существует ли файл, создать папку, получить список файлов.

import java.io.File;

public class FileExample {
    public static void main(String[] args) {
        File file = new File("/home/user/docs/notes.txt");
        
        System.out.println("Файл существует: " + file.exists());
        System.out.println("Абсолютный путь: " + file.getAbsolutePath());
        System.out.println("Размер: " + file.length() + " байт");
        
        // Создаём директорию
        File dir = new File("/home/user/new_folder");
        if (dir.mkdir()) {
            System.out.println("Папка создана");
        }
    }
}

Минус: File не умеет нормально читать большие файлы — для этого нужны потоки. И он не поддерживает символьные ссылки (soft links) из коробки. Именно поэтому Sun (а потом Oracle) выпустили NIO.

2. Чтение файлов: от InputStream до BufferedReader

Чтение — самая частая операция. Если файл текстовый, используйте BufferedReader — он буферизирует данные и работает быстро.

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class ReadFile {
    public static void main(String[] args) {
        try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.err.println("Ошибка чтения: " + e.getMessage());
        }
    }
}

Для бинарных файлов (картинки, архивы) используйте FileInputStream:

import java.io.FileInputStream;
import java.io.IOException;

public class ReadBinary {
    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("image.png")) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                // обрабатываем кусок buffer[0..bytesRead]
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Важно: всегда используйте try-with-resources — это гарантирует закрытие потока, даже если вылетит исключение.

3. Запись в файл: BufferedWriter и FileOutputStream

Запись почти симметрична чтению. Для текста — BufferedWriter, для бинарных данных — FileOutputStream.

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class WriteFile {
    public static void main(String[] args) {
        try (BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"))) {
            bw.write("Привет, мир!");
            bw.newLine();
            bw.write("Java — это мощно.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Если нужно дописать в конец файла, а не перезаписать его, используйте конструктор FileWriter(file, true).

4. Современный подход: Java NIO.2 (Path и Files)

Начиная с Java 7, появился пакет java.nio.file. Это не просто замена File, а гораздо более удобный и мощный инструмент. Ключевые классы — Path и Files.

4.1. Path — путь без боли

import java.nio.file.Path;
import java.nio.file.Paths;

public class PathExample {
    public static void main(String[] args) {
        Path path = Paths.get("/home/user", "docs", "notes.txt");
        System.out.println("Путь: " + path);
        System.out.println("Имя файла: " + path.getFileName());
        System.out.println("Родитель: " + path.getParent());
        System.out.println("Корень: " + path.getRoot());
    }
}

Paths.get() сам подставит правильный разделитель для Windows или Linux. Красота!

4.2. Files — швейцарский нож

Класс Files содержит статические методы для всего: чтение, запись, копирование, перемещение, удаление.

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.io.IOException;
import java.util.List;

public class FilesExample {
    public static void main(String[] args) throws IOException {
        Path path = Paths.get("example.txt");
        
        // Запись строк
        List<String> lines = List.of("Строка 1", "Строка 2", "Строка 3");
        Files.write(path, lines);
        
        // Чтение всех строк
        List<String> content = Files.readAllLines(path);
        content.forEach(System.out::println);
        
        // Копирование
        Path dest = Paths.get("backup.txt");
        Files.copy(path, dest, java.nio.file.StandardCopyOption.REPLACE_EXISTING);
        
        // Удаление
        Files.deleteIfExists(dest);
    }
}

Совет: Files.readAllLines() удобен для небольших файлов. Для гигантских логов лучше использовать Files.lines(), который возвращает Stream<String> и не грузит всё в память.

5. Обход файловой системы: FileVisitor и walk

Представьте: нужно найти все файлы с расширением .log в папке и её подпапках. Раньше мы писали рекурсивный обход. Теперь есть Files.walk() и Files.walkFileTree().

import java.nio.file.*;
import java.io.IOException;
import java.util.stream.Stream;

public class WalkExample {
    public static void main(String[] args) {
        Path start = Paths.get("/var/log");
        try (Stream<Path> stream = Files.walk(start)) {
            stream
                .filter(p -> p.toString().endsWith(".log"))
                .forEach(System.out::println);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Этот код выведет все файлы .log в директории /var/log и всех её поддиректориях. Элегантно, правда?

6. Работа с атрибутами и правами

В Java NIO можно легко читать и менять атрибуты файлов: размер, дата создания, права доступа.

import java.nio.file.*;
import java.nio.file.attribute.*;
import java.io.IOException;

public class AttributesExample {
    public static void main(String[] args) throws IOException {
        Path path = Paths.get("test.txt");
        
        // Чтение                

Блоги

Рекомендаций по книгам