ฉันจำเป็นต้องปิด () ทั้ง 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();

วิธีการนี้เรียกจาก servlet และฉันต้องการให้แน่ใจว่าฉันไม่เปิดมือจับไว้


4
รู้มั้ยคุณสามารถอ่านแหล่งข้อมูลเช่นนี้ได้ มันคือทั้งหมดที่มีใน src.zip ในไดเรกทอรีการติดตั้ง JDK หรือคุณสามารถอ่านแบบออนไลน์ที่เช่นdocjar.com/html/api/java/io/BufferedReader.java.html
gustafc

50
การบอกใครสักคนให้อ่านต้นฉบับนั้นแย่กว่าการพูดว่า "RTFM!" และถ้าแหล่งที่มามีข้อผิดพลาด; โดยนัยเราต้องการทราบว่าพฤติกรรมที่ถูกต้องคืออะไร?
Raedwald

1
ดี ... จากมุมมองนี้: การชี้ไปที่รายละเอียด API นั้นไม่ได้ดีไปกว่านี้แล้ว หากแหล่งที่มาไม่มีข้อผิดพลาดที่ทำให้มันไม่ทำงานเหมือนที่ระบุไว้ในเอกสารคุณจะไม่สามารถเชื่อถือเอกสารได้ ดังนั้นจึงไม่มีวิธีที่ดีในการตอบคำถามดังกล่าว
Atmocreations

@Ammocreations รีลีสการบำรุงรักษาครั้งต่อไปสามารถแก้ไขข้อบกพร่องที่คุณวางใจได้หากคุณดูที่แหล่งที่มา คุณจำเป็นต้องรู้จริงๆว่าพฤติกรรมของเอกสารคืออะไร ไม่มีอะไรผิดปกติในการดูแหล่งที่มา แต่คุณไม่สามารถถือว่าแหล่งที่มาจะไม่เปลี่ยนแปลง การเปลี่ยนแปลงพฤติกรรมที่ทำเป็นเอกสารมักจะเป็นเรื่องใหญ่กว่าการแก้ไขข้อบกพร่อง
James Moore

คำตอบ:


202

ไม่

BufferedReader.close()

ปิดสตรีมตาม javadoc สำหรับBufferedReaderและInputStreamReader

เช่นกัน

FileReader.close()

ทำ.


12
ยกเว้นว่าตัวสร้างจะBufferedReaderโยนข้อยกเว้น มันสะอาดกว่าที่จะปิดกระแสพื้นฐานแม้ว่าคุณจะต้องระวังนักตกแต่งด้วยทรัพยากรอื่น ๆ และการบัฟเฟอร์
Tom Hawtin - tackline

9
Javadoc ไม่ได้บอกว่าBufferedReader.close()ปิดเครื่องอ่านที่อยู่ข้างใต้หรือไม่ Reader.close()คำอธิบายของมันจะถูกคัดลอกเพียงจาก นี่อาจเป็นพฤติกรรมที่เกิดขึ้นจริงในทางปฏิบัติ แต่ไม่มีการบันทึกไว้
John Kugelman

3
หากพฤติกรรมที่แท้จริงแตกต่างกันควรมีการบันทึกไว้เช่น มิฉะนั้นเอกสารจะไม่มีประโยชน์ โปรแกรมเมอร์ควรพิจารณาเอกสารที่ครบถ้วนและเฉพาะเจาะจง
Atmocreations

6
ไม่สำคัญว่าเอกสารจริงควรมีการเปลี่ยนแปลงหรือไม่ควรเปลี่ยนหรือไม่Reader#close()javadoc ไม่ต้องพูดว่าปิดเอกสารหรือไม่ ทั้งหมดบอกว่าเกี่ยวข้องกับสิ่งCloses the stream and releases any system resources associated with it.ที่ไม่ชัดเจนเพียงพอที่จะบอกว่ามันทำหรือไม่ปิดทรัพยากร 'ปล่อยทรัพยากร' อาจลบการอ้างอิงใด ๆ ไปยังทรัพยากรใน BufferedReader ... ซึ่งหมายความว่าทรัพยากรจะไม่ปิด
searchengine27

99

ดังที่คนอื่น ๆ ได้ชี้ให้เห็นคุณเพียงแค่ปิดเสื้อคลุมด้านนอก

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

มีโอกาสน้อยมากที่สิ่งนี้อาจรั่วที่จับไฟล์ถ้าBufferedReaderนวกรรมิกโยนข้อยกเว้น (เช่นOutOfMemoryError ) หากแอปของคุณอยู่ในสถานะนี้ความระมัดระวังในการล้างข้อมูลของคุณอาจขึ้นอยู่กับความสำคัญว่าคุณไม่ได้กีดกันระบบปฏิบัติการของทรัพยากรที่อาจต้องการจัดสรรให้กับโปรแกรมอื่น

closeableอินเตอร์เฟซที่สามารถนำมาใช้ถ้าตัวสร้างเสื้อคลุมมีแนวโน้มที่จะล้มเหลวในชวา 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
"รหัส Java 7 ควรใช้รูปแบบลองกับทรัพยากร" ขอบคุณนั่นคือสิ่งที่ฉันกำลังมองหา วิธีแก้ปัญหานี้ถูกเขียนใน '09 ดังนั้นกระบวนทัศน์ลองกับทรัพยากรควรเป็นคำแนะนำใหม่ อีกแล้วมันให้คำตอบที่ดีกว่าสำหรับ OP มากกว่าคำตอบที่ได้รับการยอมรับ
tresf

5

ตามแหล่ง BufferedReader ในกรณีนี้ bReader.close โทร fReader.close ดังนั้นในทางเทคนิคคุณไม่จำเป็นต้องโทรหลัง


ระบุว่ามีเอกสารอธิบายถึงวิธีการใช้งานคุณควรดูเอกสารก่อน - การเบี่ยงเบนใด ๆ ในรหัสนั้นเป็นจุดบกพร่อง
hmijail mourns ลาออก

5

รหัสแหล่งที่มาสำหรับBufferedReaderแสดงให้เห็นว่าพื้นฐานถูกปิดเมื่อคุณปิด BufferedReader


1
ฉันต้องการยกนิ้วให้นี้เพื่อเชื่อมโยงกับสิ่งที่เป็นรูปธรรม แต่สิ่งนี้หมายถึงการใช้งาน OpenJDK เท่านั้นและเนื่องจาก JavaDocs ไม่ชัดเจนสำหรับReader#close()สิ่งนี้จึงไม่ได้แสดงหลักฐานที่ชัดเจนว่า Oracle JDK ตัวอย่างเช่นถูกนำมาใช้ใน แฟชั่นที่คล้ายกัน
searchengine27

4

หลังจากตรวจสอบซอร์สโค้ดฉันพบว่าตัวอย่าง:

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

วิธีการปิด () บนวัตถุBufferedReaderจะเรียกวิธีการปิดนามธรรม () ของคลาสผู้อ่านซึ่งในที่สุดจะเรียกวิธีการใช้งานในชั้นเรียนInputStreamReaderซึ่งในที่สุดก็ปิดวัตถุInputStream

ดังนั้นมีเพียง bReader.close () เท่านั้น


4
สิ่งที่ซอร์สโค้ดแสดงไม่อ้างอิงถึงการอ้างอิง เป็นสิ่งที่ข้อกำหนดระบุไว้ในกรณีนี้ Javadoc ที่สามารถพึ่งพาได้
มาร์ควิสแห่ง Lorne

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

ฉันมาสาย แต่:

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 ไม่ไม่ใช่รหัสตัวอย่าง ฉันเพิ่งเขียนบางส่วนของซอร์สโค้ดจาวา ดังนั้นหากคุณคลิกที่ฟังก์ชั่นของ BufferedReader ด้วยปุ่ม ctrl / cmd (ขึ้นอยู่กับ IDE) คุณจะเห็นซอร์สโค้ดของ BufferedReader และคุณสามารถค้นหาส่วนของรหัสนั้นได้ ดังนั้นตามที่คุณเห็น BufferedReader เพียงแค่ปิด FileReader ด้วยตัวเอง ('in' คือ FileReader ในกรณีนี้ดังนั้นเมื่อคุณเรียก bufferReader.close () มันจะเรียกใช้ใน .close () ข้างในอย่างแน่นอนใน bufferReader.close วิธี)
Dmitry Gashko

0

คุณไม่จำเป็นต้องปิดเครื่องอ่าน / เขียนที่ห่อไว้

หากคุณได้ดูเอกสาร ( Reader.close(), Writer.close()) คุณจะเห็นว่าในเอกสารReader.close()ระบุว่า:

ปิดสตรีมและปล่อยทรัพยากรระบบใด ๆ ที่เกี่ยวข้อง

ซึ่งเพิ่งบอกว่ามัน "ปล่อยทรัพยากรระบบใด ๆ ที่เกี่ยวข้องกับมัน" แม้ว่ามันจะไม่ได้รับการยืนยัน .. มันทำให้คุณเขยิบได้เพื่อเริ่มมองลึก และหากคุณไปที่Writer.close()เพียงระบุว่ามันปิดตัวเอง

ในกรณีเช่นนี้เราอ้างถึงOpenJDKเพื่อดูซอร์สโค้ด

ที่ BufferedWriter สาย 265out.close()คุณจะเห็น ดังนั้นมันจึงไม่ปิดตัวเอง .. มันเป็นอย่างอื่น ถ้าคุณค้นหาคลาสของสิ่งที่เกิดขึ้นของ " out" คุณจะสังเกตเห็นว่าในตัวสร้างที่บรรทัดที่ 87ซึ่งoutเป็นผู้เขียนคลาสจะล้อมที่ซึ่งเรียกตัวสร้างอื่นแล้วกำหนดoutพารามิเตอร์ให้กับoutตัวแปรของตัวเอง..

ดังนั้น .. แล้วคนอื่นล่ะ? คุณสามารถดูรหัสใกล้เคียงที่BufferedReader สาย 514 , BufferedInputStream สาย 468และInputStreamReader สาย 199 คนอื่น ๆ ที่ฉันไม่รู้ แต่นี่น่าจะพอที่จะถือว่าพวกเขาทำ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.