Нужно ли закрыть () и FileReader, и BufferedReader?

188

Я читаю локальный файл, используя BufferedReader, обернутый вокруг FileReader:

BufferedReader reader = new BufferedReader(new FileReader(fileName));
// read the file
// (error handling snipped)
reader.close();

Нужно ли мне , а также, или будет обертка ручки , что? Я видел код, где люди делают что-то вроде этого:close()FileReader

FileReader fReader = new FileReader(fileName);
BufferedReader bReader = new BufferedReader(fReader);
// read the file
// (error handling snipped)
bReader.close();
fReader.close();

Этот метод вызывается из сервлета, и я хотел бы убедиться, что я не оставляю открытых дескрипторов.

Zilk
источник
4
Знаешь, ты можешь просто прочитать источник информации, подобной этой. Все это есть в src.zip в каталоге установки JDK, или вы можете прочитать его онлайн, например, на docjar.com/html/api/java/io/BufferedReader.java.html
gustafc
50
Говорить кому-либо о прочтении источника хуже, чем говорить «RTFM!». А что если в источнике есть ошибка; неявно мы хотим знать, что такое правильное поведение?
Raedwald
1
Ну ... с этой точки зрения: указание на спецификации API не лучше, чем тогда. Если в источнике нет ошибки, из-за которой он не ведет себя так, как указано в документах, вы не можете полагаться на документы. Так что нет хорошего способа ответить на такой вопрос.
Atmocreations
@ Atmocreations В следующем техническом выпуске может быть исправлена ​​ошибка, на которую вы можете положиться, если просто посмотрите на источник. Вам действительно нужно знать, что такое документированное поведение. Конечно, нет ничего плохого в том, чтобы смотреть на источник, но вы не можете предполагать, что источник не изменится. Изменение документированного поведения обычно намного сложнее, чем исправление ошибки.
Джеймс Мур

Ответы:

202

нет.

BufferedReader.close()

закрывает поток в соответствии с javadoc для BufferedReader и InputStreamReader

так же как

FileReader.close()

делает.

Atmocreations
источник
12
Разве что конструктор BufferedReaderбросает исключение. Лучше просто закрыть основной поток, хотя вам нужно остерегаться декораторов с другими ресурсами и буферизацией.
Том Хотин - tackline
9
Javadoc не говорит, BufferedReader.close()закрывает ли основной читатель. Его описание просто скопировано с Reader.close(). Это может быть фактическим поведением на практике, но это не задокументировано.
Джон Кугельман
3
Если фактическое поведение было другим, то это должно было быть задокументировано как таковое. В противном случае документация бесполезна. Программист должен иметь возможность рассматривать документацию как полную и конкретную.
Atmocreations
6
Неважно, должна ли была изменена фактическая документация или не должна быть изменена, Reader#close()javadoc не говорит, закрывает ли она это обернутый Reader или нет. Все, что он говорит, относится к тому, Closes the stream and releases any system resources associated with it.что недостаточно ясно, чтобы сказать, что он закрывает или закрывает ресурс. «Освободить ресурс» может также удалить любую ссылку на ресурс в BufferedReader ... что будет означать, что ресурс не закрыт.
searchengine27
99

Как уже отмечали другие, вам нужно только закрыть внешнюю обертку.

BufferedReader reader = new BufferedReader(new FileReader(fileName));

Существует очень малая вероятность того, что это может привести к утечке дескриптора файла, если BufferedReader конструктор выдает исключение (например OutOfMemoryError). Если ваше приложение находится в этом состоянии, то насколько тщательной должна быть ваша очистка, может зависеть от того, насколько важно не лишать ОС ресурсов, которые она может захотеть выделить другим программам.

Интерфейс Closeable можно использовать, если конструктор-обертка в Java 5 или 6 может потерпеть неудачу:

Reader reader = new FileReader(fileName);
Closeable resource = reader;
try {
  BufferedReader buffered = new BufferedReader(reader);
  resource = buffered;
  // TODO: input
} finally {
  resource.close();
}

Код Java 7 должен использовать шаблон try-with-resources :

try (Reader reader = new FileReader(fileName);
    BufferedReader buffered = new BufferedReader(reader)) {
  // TODO: input
}
Макдауэлл
источник
1
Msgstr "Код Java 7 должен использовать шаблон try-with-resources". Спасибо, это именно то, что я искал. Это решение было написано в '09, поэтому парадигма попытки с ресурсами, вероятно, должна быть новой рекомендацией. Кроме того, он предлагает лучший ответ ФП по сравнению с принятым и более высоко оцененным ответом.
tresf
5

Согласно источнику BufferedReader, в этом случае bReader.close вызывает fReader.close, поэтому технически вам не нужно вызывать последний.

Csaba_H
источник
Учитывая, что есть документация, объясняющая, как ее следует использовать, вы должны сначала посмотреть документацию - любое отклонение в коде является ошибкой.
hmijail скорбит по отставке
5

Исходный код для BufferedReader показывает, что базовый уровень закрывается при закрытии BufferedReader.

Брайан Агнью
источник
1
Я действительно хочу поблагодарить за ссылку на что-то конкретное, но это относится только к реализации OpenJDK, и поскольку JavaDocs неясны Reader#close(), это не дает конкретного доказательства того, что Oracle JDK, например, реализован в похожая мода.
searchengine27
4

После проверки исходного кода я обнаружил, что для примера:

FileReader fReader = new FileReader(fileName);
BufferedReader bReader = new BufferedReader(fReader);

метод close () объекта BufferedReader будет вызывать абстрактный метод close () класса Reader, который в конечном итоге вызовет реализованный метод в классе InputStreamReader , который затем закроет объект InputStream .

Таким образом, достаточно только bReader.close ().

Ануп Верма
источник
4
То, что показывает исходный код, не цитируется в качестве ссылки. Это то, что говорится в спецификации , в данном случае Javadoc, на что можно положиться.
Маркиз Лорн
1

Начиная с Java 7 вы можете использовать оператор try-with-resources

try (BufferedReader br = new BufferedReader(new FileReader(path))) {
    return br.readLine();
}

Поскольку BufferedReaderэкземпляр объявлен в операторе try-with-resource, он будет закрыт независимо от того, завершается ли оператор try нормально или внезапно. Так что вам не нужно закрывать это сами в finallyзаявлении. (Это также касается вложенных операторов ресурсов)

Это рекомендуемый способ работы с ресурсами, более подробную информацию смотрите в документации.

Клаудиу
источник
Это почти идентично ответу @ mcdowell от 2009 года, который также охватывает некоторые проблемы, которые могут возникнуть.
tresf
0

Вам нужно только закрыть bufferedReader, т.е. reader.close (), и он будет работать нормально.

Jitendra
источник
0

Я опоздал, но:

BufferReader.java:

public BufferedReader(Reader in) {
  this(in, defaultCharBufferSize);
}

(...)

public void close() throws IOException {
    synchronized (lock) {
        if (in == null)
            return;
        try {
            in.close();
        } finally {
            in = null;
            cb = null;
        }
    }
}
Дмитрий Гашко
источник
Ээээ, это не отвечает на его / ее вопрос? Она / он спрашивает, нужно ли закрыть FileReader и BufferedReader, а не пример кода.
TornaxO7
@ TornaxO7 нет, это не пример кода. Я только что написал часть исходного кода Java. Итак, если вы щелкнете по какой-либо функции BufferedReader с помощью клавиши ctrl / cmd (зависит от IDE), вы увидите исходный код BufferedReader и сможете найти этот фрагмент кода. Итак, как вы можете видеть, BufferedReader просто закрывает FileReader сам по себе (в этом случае 'in' является FileReader, поэтому, когда вы вызываете bufferReader.close (), он вызывает in.close () внутри, именно в методе bufferReader.close)
Dmitry Гашко
0

Вам не нужно закрывать завернутый читатель / писатель.

Если вы взглянули на документы ( Reader.close(), Writer.close()), вы увидите, что в Reader.close()них написано:

Закрывает поток и освобождает любые системные ресурсы, связанные с ним.

Который просто говорит, что он «освобождает любые системные ресурсы, связанные с ним». Даже если это не подтверждает ... это дает вам толчок, чтобы начать смотреть глубже. и если вы идете к Writer.close()нему, только утверждает, что он закрывается сам.

В таких случаях мы обращаемся к OpenJDK, чтобы взглянуть на исходный код.

На BufferedWriter Line 265 вы увидите out.close(). Так что это не закрытие себя .. Это что-то еще. Если вы будете искать в классе вхождения " out", вы заметите, что в конструкторе в строке 87, который outявляется писателем, класс переносится туда, где он вызывает другого конструктора, а затем присваивает outпараметр своей собственной outпеременной ..

Так что .. как насчет других? Вы можете увидеть похожий код в строке BufferedReader 514 , строке BufferedInputStream 468 и строке 199 InputStreamReader . Других я не знаю, но этого должно быть достаточно, чтобы предположить, что они знают.

Омар Абдул Азиз
источник