2010-10-21 105 views
56

當使用Java InputStreams時,我對使用close()方法有一些疑問。從我看到並從大多數開發人員那裏閱讀的內容中,當不再需要時,您應該始終在InputStream上顯式調用close()。但是,今天我一直在尋找到使用Java屬性文件,我發現每個實例有這樣的事情:關閉Java InputStreams

Properties props = new Properties(); 
try { 
    props.load(new FileInputStream("message.properties")); 
    //omitted. 
} catch (Exception ex) {} 

通過上面的例子,有沒有辦法來明確調用close(),因爲InputStream爲使用後無法訪問。我已經看到了InputStream的許多類似用法,儘管它似乎與大多數人關於明確關閉的內容相矛盾。我通過Oracle的JavaDocs閱讀,並沒有提到Properties.load()方法是否關閉了InputStream。我想知道如果這通常是可以接受的,或者最好是做一些更類似如下:

Properties props = new Properties(); 
InputStream fis = new FileInputStream("message.properties"); 
try { 
    props.load(fis); 
    //omitted. 
} catch (Exception ex) { 
    //omitted. 
} finally { 
    try { 
     fis.close(); 
    } catch (IOException ioex) { 
     //omitted. 
    } 
} 

哪種方式更好和/或更有效?還是它真的很重要?

+0

感謝大家爲你提供的答案。我希望我能接受他們所有的答案。這對我來說很有意義。 – 2010-10-21 20:59:42

回答

21

Properties Tutorial例子關閉FileInputStream加載後明確,所以我認爲它是安全的假設load方法是不負責的,你是。

// create and load default properties 
Properties defaultProps = new Properties(); 
FileInputStream in = new FileInputStream("defaultProperties"); 
defaultProps.load(in); 
in.close(); 

僅供參考,我查了Apache Harmony實施Properties,它也關閉負載流。

+0

屬性教程是我所希望的解釋。感謝您的鏈接! – 2010-10-21 20:52:06

7

它看起來像第一個代碼示例最終依靠FileInputStream中的finalize方法來實際關閉文件。我會說你的第二個例子更好,即使在這兩種情況下文件都會關閉。

有些情況下,比如字節流,close什麼都不做,可以省略,否則我認爲最好在finally塊中顯式關閉文件。如果你打開它,你可以關閉它。

有一本書對Oracle的網站叫Java Platform Performance,討論其附錄中終結,它說:

你幾乎總是更好做自己的清除,而不是依靠一個終結的。使用終結器也可能會留下不能在無限期的時間內恢復的關鍵資源。如果您正在考慮使用終結器來確保及時釋放重要資源,那麼您可能需要重新考慮。

12

在文檔中沒有提到props.load會關閉輸入流。你應該像你所建議的那樣,在finally塊中手動關閉輸入流。

函數關閉InputStream是不正常的。相同的約定適用於非垃圾回收語言中的內存:如果可能,打開該流的人應該關閉該流。否則,很容易讓一個流打開(你認爲一個函數會關閉它,但它不會,或者其他東西)

+0

+1「打開流的人應該關閉流」如果這是不可能的,方法評論應該指示調用者這樣做。第一個代碼示例是不好的做法。 – leonbloy 2010-10-21 20:36:30

+0

Java 1.6的最新補丁版本對'props.load(Reader)'有這樣的評論:*在這個方法返回後,指定的流保持打開狀態*在我發現這個問答之前,我有TL; DR'd'docs for' props.load(Reader)'並且無法理解爲什麼我的流仍然是開放的! – kevinarpe 2013-10-07 08:33:14

42

Properties類將輸入流包裝在LineReader中以讀取屬性文件。由於您提供了輸入流,因此您有責任關閉它。

第二個例子是一個更好的方式來處理流,遠不要依靠別人來關閉它。

的一個改進,你可以做就是用IOUtils.closeQuietly()

http://commons.apache.org/io/api-1.2/org/apache/commons/io/IOUtils.html#closeQuietly(java.io.InputStream)

關閉流,例如:

Properties props = new Properties(); 
InputStream fis = new FileInputStream("message.properties"); 
try { 
    props.load(fis); 
    //omitted. 
} catch (Exception ex) { 
    //omitted. 
} finally { 
    IOUtils.closeQuietly(fis); 
} 
+10

+1爲'closeQuietly'。 – uckelman 2010-10-21 20:54:42

+0

不要在IOUtils 2.6上使用,不推薦使用,也不要使用替換。 「請使用try-with-resources語句或手動處理抑制的異常。」 – Sergio 2018-02-12 15:32:57

2

讓我給他人的答案添加一點點。

如果你可以導入Apache Commons IO,你可以利用以往那麼得心應手AutoCloseInputStream小號類:你包你InputStream,然後你只需要使用你的包裹實例,它就會立即自動關閉,作爲輸入端有已達到或流明確關閉時,以先到者爲準。

19

我會去嘗試,用資源(至少對Java 7+):

Properties props = new Properties(); 

try(InputStream fis = new FileInputStream("message.properties")) { 
    props.load(fis); 
    //omitted. 
} catch (Exception ex) { 
    //omitted. 
} 

的密切()調用應該在try塊退出被自動調用。

+0

+1:陳舊的問題,但谷歌命中的相關信息。 – tilpner 2014-07-28 18:48:18

9

如果您使用的是Java 7+您可以使用此:

try(InputStream is = new FileInputStream("message.properties")) { 
    // ... 
}