← Назад к вопросам

Как закрыть открытый файл, если появится исключение

1.6 Junior🔥 151 комментариев
#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Как закрыть открытый файл при исключении

Проблема

Если файл открыт и при обработке данных возникает исключение, ресурс может оказаться незакрытым и произойдёт утечка памяти. Нужно гарантировать закрытие файла в любом случае.

Решение 1: Try-Finally (классический подход)

Допускает утечки, если исключение возникнет в блоке finally:

FileInputStream fis = null;
try {
    fis = new FileInputStream("file.txt");
    // обработка данных
    int data = fis.read();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (fis != null) {
        try {
            fis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Минусы: громоздко, легко ошибиться, утечки возможны

Решение 2: Try-With-Resources (Java 7+) ✓ РЕКОМЕНДУЕТСЯ

Автоматически закрывает любые ресурсы, реализующие AutoCloseable:

try (FileInputStream fis = new FileInputStream("file.txt")) {
    byte[] data = new byte[1024];
    int bytesRead = fis.read(data);
    System.out.println("Прочитано: " + bytesRead + " байт");
} catch (IOException e) {
    System.err.println("Ошибка чтения: " + e.getMessage());
}
// Файл автоматически закрыт, даже если было исключение

Преимущества:

  • Автоматическое закрытие в любом случае
  • Чистый и читаемый код
  • Несколько ресурсов одновременно
  • Подавление исключений (suppressed exceptions)

Решение 3: Несколько ресурсов в Try-With-Resources

try (FileInputStream fis = new FileInputStream("input.txt");
     FileOutputStream fos = new FileOutputStream("output.txt")) {
    byte[] buffer = new byte[1024];
    int bytesRead;
    while ((bytesRead = fis.read(buffer)) != -1) {
        fos.write(buffer, 0, bytesRead);
    }
} catch (IOException e) {
    System.err.println("Ошибка копирования: " + e.getMessage());
}
// Оба файла закроются в правильном порядке (в обратном)

Решение 4: С BufferedReader

try (BufferedReader reader = new BufferedReader(
        new FileReader("data.txt"))) {
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }
} catch (IOException e) {
    System.err.println("Ошибка: " + e.getMessage());
}

Как работает Try-With-Resources под капотом

Compiler преобразует этот код:

try (FileInputStream fis = new FileInputStream("file.txt")) {
    // код
} catch (IOException e) {
    e.printStackTrace();
}

В примерно такой:

FileInputStream fis = new FileInputStream("file.txt");
Throwable suppressed = null;
try {
    // код
} catch (Throwable t) {
    suppressed = t;
    throw t;
} finally {
    if (fis != null) {
        if (suppressed != null) {
            try {
                fis.close();
            } catch (Throwable t) {
                suppressed.addSuppressed(t);
            }
        } else {
            fis.close();
        }
    }
}

Интерфейс AutoCloseable

Для собственных ресурсов реализуй AutoCloseable:

public class MyResource implements AutoCloseable {
    @Override
    public void close() throws Exception {
        // логика закрытия
        System.out.println("Ресурс закрыт");
    }
}

// Использование
try (MyResource resource = new MyResource()) {
    // работаем с ресурсом
} catch (Exception e) {
    e.printStackTrace();
}

Проверка suppressed exceptions

try (FileInputStream fis = new FileInputStream("file.txt")) {
    throw new IOException("Основная ошибка");
} catch (IOException e) {
    System.out.println("Основное исключение: " + e.getMessage());
    for (Throwable suppressed : e.getSuppressed()) {
        System.out.println("Подавленное исключение: " + suppressed.getMessage());
    }
}

Важные моменты

  1. Try-with-resources — всегда выбор номер 1 для управления ресурсами
  2. AutoCloseable должен реализовывать любой класс, управляющий ресурсами
  3. Порядок закрытия — обратный порядку открытия
  4. Suppressed exceptions — исключения при закрытии не теряются
  5. Многоуровневые потоки — не забывай закрывать внешние обёртки

Anti-pattern: Игнорирование ошибок закрытия

// ❌ ПЛОХО
try (FileInputStream fis = new FileInputStream("file.txt")) {
    // код
} catch (IOException e) {
    // ignore
}
// Исключения при close() тоже будут проигнорированы!

Всегда обрабатывай исключения при закрытии или знай, что ты делаешь.

Как закрыть открытый файл, если появится исключение | PrepBro