Чи потрібно мені закрити () і 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();

Цей метод викликається сервлетом, і я хотів би переконатися, що я не залишаю жодної ручки відкритою.


4
Знаєте, ви можете просто прочитати джерело для такої інформації. Це все є у src.zip в каталозі встановлення JDK, або ви можете прочитати його в Інтернеті, наприклад, docjar.com/html/api/java/io/BufferedReader.java.html
gustafc

50
Сказати комусь прочитати джерело - гірше, ніж сказати "RTFM!". А що, якщо в джерелі є помилка; ми неявно хочемо знати, що таке правильна поведінка?
Raedwald

1
Ну ... з цієї точки зору: вказівка ​​на специфікації API не краща. Якщо джерело не має помилки, що призводить до того, що він не веде себе так, як зазначено в документах, ви не можете покластися на документи. Тож немає хорошого способу відповісти на таке питання.
Амокреації

@Atmocreations Наступний випуск технічного обслуговування може весело виправити помилку, на яку ви покладаєтесь, якщо просто подивитись на джерело. Вам дійсно потрібно знати, що таке документальне поведінка. Звичайно, нічого поганого в пошуку джерела, але ви не можете припустити, що джерело не зміниться. Зміна задокументованої поведінки зазвичай набагато більша справа, ніж виправлення помилки.
Джеймс Мур

Відповіді:


202

немає.

BufferedReader.close()

закриває потік відповідно до javadoc для BufferedReader та InputStreamReader

так само, як

FileReader.close()

робить.


12
Якщо тільки конструктор не BufferedReaderкине виняток. Чистіше просто закрити основний потік, хоча потрібно стежити за декораторами з іншими ресурсами та буферизацією.
Том Хотін - тайклін

9
Javadoc не каже, чи BufferedReader.close()закриває основний читач. Його опис просто скопійовано з Reader.close(). Це може бути реальна поведінка на практиці, але це не документально підтверджено.
Джон Кугельман

3
Якби фактична поведінка була іншою, то вона мала бути зафіксована як така. Інакше документація марна. Програміст повинен мати можливість розглядати документацію як повну та конкретну.
Амокреації

6
Не має значення, чи слід було змінити фактичну документацію чи не слід її змінювати, Reader#close()javadoc не говорить про те, закриває вона чи ні завершений читання чи ні. Все, про що йдеться, пов'язане з тим, Closes the stream and releases any system resources associated with it.що є недостатньо явним, щоб сказати, що він працює або не закриває ресурс. "Звільнити ресурс" може також також видалити будь-яку посилання на ресурс в BufferedReader ..., що означає, що ресурс не закритий.
searchchengine27

99

Як вказували інші, потрібно лише закрити зовнішню обгортку.

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

Є дуже малий шанс, що це може витікати ручку файлу, якщо BufferedReaderконструктор кине виняток (наприклад OutOfMemoryError). Якщо ваша програма перебуває в такому стані, то, наскільки обережна потреба в очищенні, може залежати від того, наскільки важливим є те, що ви не позбавляєте ОС ресурсів, які вона може захотіти виділити іншим програмам.

Інтерфейс, що закривається, може використовуватися, якщо конструктор обгортки, ймовірно, не працює в 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 (Reader reader = new FileReader(fileName);
    BufferedReader buffered = new BufferedReader(reader)) {
  // TODO: input
}

1
"Код Java 7 повинен використовувати шаблон пробного використання ресурсів". Дякую, саме це я шукав. Це рішення було написане у '09 році, тому парадигма пробних ресурсів, мабуть, повинна бути новою рекомендацією. Крім того, він пропонує кращу відповідь на ОП щодо прийнятої та більш високої проголосованої відповіді.
tresf

5

За даними джерела BufferedReader, у цьому випадку bReader.close викликає fReader.close технічно, що вам не доведеться дзвонити останньому.


З огляду на те, що існує документація, яка пояснює, як її використовувати, слід спочатку переглянути документацію - будь-яке відхилення в коді є помилкою.
hmijail сумує у відставці

5

Вихідний код BufferedReader показує, що базовий елемент закритий, коли ви закриваєте BufferedReader.


1
Мені дуже хочеться зробити це великим пальцем для прив'язки до чогось конкретного, але це стосується лише реалізації OpenJDK, і оскільки JavaDocs незрозумілий Reader#close(), це не дає конкретних доказів того, що, наприклад, JDK Oracle реалізований у подібна мода.
searchchengine27

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 (BufferedReader br = new BufferedReader(new FileReader(path))) {
    return br.readLine();
}

Оскільки BufferedReaderекземпляр оголошений у операторі спробу використання ресурсу, він буде закритий незалежно від того, виконати випробування нормально або різко. Тож вам не потрібно закривати це самостійно у finallyвиписці. (Це також стосується вкладених заяв про ресурси)

Це рекомендований спосіб роботи з ресурсами, детальну інформацію див. У документації


Це майже ідентично відповіді @ mcdowell з 2009 року, яка також охоплює деякі проблеми, які можуть виникнути в кращому випадку.
tresf

0

Вам потрібно лише закрити bufferedReader, тобто reader.close (), і він буде добре працювати.


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;
        }
    }
}

Eeeeh, що не відповідає на його запитання? Вона / Він запитує, чи потрібно закривати FileReader і BufferedReader не прикладним кодом.
TornaxO7

@ TornaxO7 ні, це не приклад коду. Я щойно написав частину вихідного коду Java. Отже, якщо натиснути якусь функцію BufferedReader за допомогою клавіші ctrl / cmd (залежить від IDE), ви побачите вихідний код BufferedReader, і ви зможете знайти цей фрагмент коду. Отже, як ви можете бачити BufferedReader, просто закрийте FileReader сам по собі ("in" - це FileReader в цьому випадку, тож, коли ви викликаєте bufferReader.close (), він викликає in.close () всередині, точно в методі bufferReader.close)
Дмитро Гашко

0

Вам не потрібно закривати загорнутий читач / письменник.

Якщо ви подивилися на документи ( Reader.close(), Writer.close()), ви побачите, що в Reader.close()ньому написано:

Закриває потік і вивільняє будь-які системні ресурси, пов'язані з ним.

Що просто говорить, що "вивільняє будь-які системні ресурси, пов'язані з ним". Незважаючи на те, що це не підтверджує .. це дає вам поштовх, щоб почати дивитися глибше. і якщо ви переходите до Writer.close()нього, то тільки заявляєте, що він закривається сам.

У таких випадках ми звертаємось до OpenJDK, щоб переглянути вихідний код.

На BufferedWriter Line 265 ви побачите out.close(). Так що це не закриває себе .. Це щось інше. Якщо ви шукаєте в класі виникнення " out", ви помітите, що в конструкторі в рядку 87, що outпише, клас загортається там, де він викликає інший конструктор, а потім призначає outпараметр своєму власномуout змінної.

Отже .. А як щодо інших? Ви можете побачити подібний код на BufferedReader Line 514 , BufferedInputStream Line 468 та InputStreamReader Line 199 . Інших я не знаю, але цього має бути достатньо, щоб припустити, що вони так роблять.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.