Tôi có cần phải đóng () cả FileReader và BufferedReader không?


188

Tôi đang đọc một tệp cục bộ bằng cách sử dụng BufferedReader bao quanh FileReader:

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

Tôi có cần phải close()sự FileReaderlà tốt, hoặc sẽ wrapper xử lý đó? Tôi đã thấy mã nơi mọi người làm một cái gì đó như thế này:

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

Phương thức này được gọi từ một servlet và tôi muốn đảm bảo rằng tôi không để bất kỳ tay cầm nào mở.


4
Vâng, bạn chỉ có thể đọc nguồn cho thông tin như thế này. Đó là tất cả có trong src.zip trong thư mục cài đặt JDK hoặc bạn có thể đọc trực tuyến tại ví dụ docjar.com/html/api/java/io/BufferedReader.java.html
gustafc

50
Nói ai đó đọc nguồn còn tệ hơn nói "RTFM!". Và nếu nguồn có lỗi; ngầm chúng ta muốn biết hành vi đúng là gì?
Raedwald

1
Chà ... từ quan điểm này: chỉ vào thông số API không tốt hơn sau đó. Nếu nguồn không có lỗi gây ra rằng nó không hoạt động như được chỉ định trong tài liệu, bạn không thể dựa vào tài liệu. Vì vậy, không có cách nào tốt để trả lời một câu hỏi như vậy.
Atmocreations

@Atmocreations Bản phát hành bảo trì tiếp theo có thể vui vẻ sửa một lỗi mà bạn dựa vào nếu bạn chỉ nhìn vào nguồn. Bạn thực sự cần phải biết hành vi được ghi lại là gì. Tất nhiên, không có gì sai khi nhìn vào nguồn, nhưng bạn không thể cho rằng nguồn sẽ không thay đổi. Thay đổi hành vi tài liệu thường là một nhiều thỏa thuận lớn hơn sửa chữa một lỗi.
James Moore

Câu trả lời:


202

Không.

BufferedReader.close()

đóng luồng theo javadoc cho BufferedReaderInputStreamReader

cũng như

FileReader.close()

làm.


12
Trừ khi các nhà xây dựng để BufferedReaderném một ngoại lệ. Nó sạch hơn chỉ để đóng luồng bên dưới, mặc dù bạn cần coi chừng các nhà trang trí với các tài nguyên và bộ đệm khác.
Tom Hawtin - tackline

9
Javadoc không cho biết có BufferedReader.close()đóng trình đọc bên dưới hay không. Mô tả của nó chỉ đơn giản là sao chép từ Reader.close(). Đây có thể là hành vi thực tế trong thực tế, nhưng nó không được ghi lại.
John Kugelman

3
Nếu hành vi thực tế là khác nhau, thì nó đã được ghi lại như vậy. Nếu không thì tài liệu là vô dụng. Các lập trình viên nên có thể coi tài liệu là đầy đủ và cụ thể.
Atmocreations

6
Không quan trọng là tài liệu thực tế nên được thay đổi hay không nên thay đổi, Reader#close()javadoc không nói liệu nó có đóng nó hay không. Tất cả những gì nó nói liên quan đến điều Closes the stream and releases any system resources associated with it.đó là không đủ rõ ràng để nói rằng nó có hoặc không đóng tài nguyên. 'Giải phóng tài nguyên' cũng có thể xóa bất kỳ tham chiếu nào đến tài nguyên trong BufferedReader ... điều đó có nghĩa là tài nguyên không bị đóng.
searchengine27

99

Như những người khác đã chỉ ra, bạn chỉ cần đóng lớp bọc bên ngoài.

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

Có một cơ hội rất nhỏ rằng điều này có thể rò rỉ xử lý tệp nếu nhà BufferedReaderxây dựng đã ném ngoại lệ (ví dụ OutOfMemoryError). Nếu ứng dụng của bạn ở trạng thái này, việc dọn dẹp của bạn cần cẩn thận đến mức nào tùy thuộc vào mức độ nghiêm trọng của việc bạn không tước đi hệ điều hành tài nguyên mà nó có thể muốn phân bổ cho các chương trình khác.

Các thể đóng giao diện có thể được sử dụng nếu một constructor wrapper là khả năng thất bại trong Java 5 hoặc 6:

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

Mã Java 7 nên sử dụng mẫu thử với tài nguyên :

try (Reader reader = new FileReader(fileName);
    BufferedReader buffered = new BufferedReader(reader)) {
  // TODO: input
}

1
"Mã Java 7 nên sử dụng mẫu thử với tài nguyên". Cảm ơn, đó chính xác là những gì tôi đang tìm kiếm. Giải pháp này được viết vào năm09, vì vậy mô hình thử tài nguyên có lẽ nên là đề xuất mới. Furthemore, nó cung cấp một câu trả lời tốt hơn cho OP qua câu trả lời được chấp nhận và được bình chọn cao hơn.
tresf

5

Theo nguồn BufferedReader, trong trường hợp này, bReader.c Đóng gọi fReader.c Đóng để về mặt kỹ thuật, bạn không phải gọi sau.


Cho rằng có tài liệu giải thích cách sử dụng nó, bạn nên xem tài liệu trước - bất kỳ sai lệch nào trong mã là một lỗi.
hmijail thương tiếc những người từ chức

5

Mã nguồn cho BufferedReader cho thấy phần bên dưới bị đóng khi bạn đóng BufferedReader.


1
Tôi thực sự muốn đưa ra ý kiến ​​này để liên kết với một cái gì đó cụ thể, nhưng điều này chỉ đề cập đến việc triển khai OpenJDK và vì JavaDocs không rõ ràng Reader#close(), ví dụ, điều này không cung cấp bằng chứng cụ thể rằng JDK của Oracle được triển khai trong một thời trang tương tự.
searchengine27

4

Sau khi kiểm tra mã nguồn, tôi thấy rằng ví dụ:

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

phương thức close () trên đối tượng BufferedReader sẽ gọi phương thức close () trừu tượng của lớp Reader mà cuối cùng sẽ gọi phương thức được triển khai trong InputStreamReader lớp , sau đó đóng đối tượng InputStream .

Vì vậy, chỉ bReader.close () là đủ.


4
Những gì mã nguồn hiển thị không phải là tài liệu tham khảo. Đó là những gì đặc tả nói, trong trường hợp này là Javadoc, có thể dựa vào.
Hầu tước Lorne

1

Bắt đầu từ Java 7, bạn có thể sử dụng Tuyên bố thử tài nguyên

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

Bởi vì BufferedReadercá thể được khai báo trong câu lệnh try-with-resource, nó sẽ bị đóng bất kể câu lệnh try hoàn thành bình thường hay đột ngột. Vì vậy, bạn không cần phải đóng nó trong finallytuyên bố. (Đây cũng là trường hợp với các báo cáo tài nguyên lồng nhau)

Đây là cách được khuyến nghị để làm việc với các tài nguyên, xem tài liệu để biết thêm thông tin chi tiết


Điều này gần giống với câu trả lời của @ mcdowell từ năm 2009, cũng bao gồm một số vấn đề trường hợp có thể xảy ra.
tresf

0

Bạn chỉ cần đóng bộ đệm, tức là reader.close () và nó sẽ hoạt động tốt.


0

Tôi đến trễ, nhưng:

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 mà không trả lời câu hỏi của anh ấy / cô ấy? Cô ấy / anh ấy hỏi có cần thiết phải đóng FileReader và BufferedReader không phải là mã ví dụ.
TornaxO7

@ TornaxO7 không, đây không phải là mã ví dụ. Tôi chỉ viết một phần của mã nguồn java. Vì vậy, nếu bạn nhấp vào một số chức năng của BufferedReader bằng khóa ctrl / cmd (phụ thuộc vào IDE), bạn có thể thấy mã nguồn của BufferedReader và bạn có thể tìm thấy đoạn mã đó. Vì vậy, như bạn có thể thấy BufferedReader chỉ cần đóng FileReader một mình ('in' là FileReader trong trường hợp này, vì vậy, khi bạn gọi đệmReader.close (), nó gọi in.close () bên trong, chính xác là trong phương thức đệmReader.close)
Dmitry Gashko

0

Bạn không cần phải đóng trình đọc / nhà văn được bao bọc.

Nếu bạn đã xem các tài liệu ( Reader.close(), Writer.close()), bạn sẽ thấy trong Reader.close()đó có ghi:

Đóng luồng và giải phóng bất kỳ tài nguyên hệ thống nào được liên kết với nó.

Mà chỉ nói rằng nó "giải phóng bất kỳ tài nguyên hệ thống liên quan đến nó". Mặc dù nó không xác nhận .. nó mang lại cho bạn một chút để bắt đầu nhìn sâu hơn. và nếu bạn đi đến Writer.close()nó chỉ nói rằng nó tự đóng lại.

Trong những trường hợp như vậy, chúng tôi tham khảo OpenJDK để xem mã nguồn.

Tại BufferedWriter Line 265 bạn sẽ thấy out.close(). Vì vậy, nó không tự đóng cửa .. Đó là một cái gì đó khác. Nếu bạn tìm kiếm lớp cho các lần xuất hiện của " out", bạn sẽ nhận thấy rằng trong hàm tạo của Dòng 87 , đó outlà lớp ghi, trong đó nó gọi hàm xây dựng khác và sau đó gán outtham số cho chính nóout biến .

Vậy .. Còn người khác thì sao? Bạn có thể thấy mã tương tự tại BufferedReader Line 514 , BufferedInputStream Line 468InputStreamReader Line 199 . Những người khác tôi không biết nhưng điều này là đủ để cho rằng họ làm.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.