日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java关闭io流_Java IO流关闭问题的深入研究

發布時間:2024/9/30 java 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java关闭io流_Java IO流关闭问题的深入研究 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

前幾天看了一篇文章(見參考文章),自己動手試了下,發現有些不一樣結論,作博客記錄下,本文主要研究兩個問題:

1、包裝流的close方法是否會自動關閉被包裝的流?

答:會。

2、關閉流方法是否有順序?

答:無。

一、包裝流的close方法是否會自動關閉被包裝的流?

平時我們使用輸入流和輸出流一般都會使用buffer包裝一下,

直接看下面代碼(這個代碼運行正常,不會報錯)

importjava.io.BufferedOutputStream;importjava.io.FileOutputStream;importjava.io.IOException;public classIOTest {public static void main(String[] args) throwsIOException {

FileOutputStream fileOutputStream= new FileOutputStream("c:\\a.txt");

BufferedOutputStream bufferedOutputStream= newBufferedOutputStream(fileOutputStream);

bufferedOutputStream.write("test write something".getBytes());

bufferedOutputStream.flush();//從包裝流中關閉流

bufferedOutputStream.close();

}

}

下面我們來研究下這段代碼的bufferedOutputStream.close();方法是否調用了fileOutputStream.close();

先看BufferedOutputStream源代碼:

public class BufferedOutputStream extends FilterOutputStream { ...

可以看到它繼承FilterOutputStream,并且沒有重寫close方法,

所以直接看FilterOutputStream的源代碼:

public void close() throwsIOException {try{

flush();

}catch(IOException ignored) {

}

out.close();

}

跟蹤out(FilterOutputStream中):

protectedOutputStream out;publicFilterOutputStream(OutputStream out) {this.out =out;

}

再看看BufferedOutputStream中:

publicBufferedOutputStream(OutputStream out) {this(out, 8192);

}public BufferedOutputStream(OutputStream out, intsize) {super(out);if (size <= 0) {throw new IllegalArgumentException("Buffer size <= 0");

}

buf= new byte[size];

}

可以看到BufferedOutputStream調用super(out);,也就是說,out.close();調用的是通過BufferedOutputStream傳入的被包裝的流,這里就是FileOutputStream。

我們在看看其他類似的,比如BufferedWriter的源代碼:

public void close() throwsIOException {synchronized(lock) {if (out == null) {return;

}try{

flushBuffer();

}finally{

out.close();

out= null;

cb= null;

}

}

}

通過觀察各種流的源代碼,可得結論:包裝的流都會自動調用被包裝的流的關閉方法,無需自己調用。

關閉流方法是否有順序?

由上面的結論,就會產生一個問題:如果手動關閉被包裝流會怎么樣,這個關閉流有順序嗎?而實際上我們習慣都是兩個流都關閉的。

首先我們來做一個簡單的實驗,基于第一個問題的代碼上增加手動增加關閉流的代碼,那么就有兩種順序:

1.先關閉被包裝流(正常沒異常拋出)

importjava.io.BufferedOutputStream;importjava.io.FileOutputStream;importjava.io.IOException;public classIOTest {public static void main(String[] args) throwsIOException {

FileOutputStream fileOutputStream= new FileOutputStream("c:\\a.txt");

BufferedOutputStream bufferedOutputStream= newBufferedOutputStream(fileOutputStream);

bufferedOutputStream.write("test write something".getBytes());

bufferedOutputStream.flush();

fileOutputStream.close();//先關閉被包裝流

bufferedOutputStream.close();

}

}

2.先關閉包裝流(正常沒異常拋出)

importjava.io.BufferedOutputStream;importjava.io.FileOutputStream;importjava.io.IOException;public classIOTest {public static void main(String[] args) throwsIOException {

FileOutputStream fileOutputStream= new FileOutputStream("c:\\a.txt");

BufferedOutputStream bufferedOutputStream= newBufferedOutputStream(fileOutputStream);

bufferedOutputStream.write("test write something".getBytes());

bufferedOutputStream.flush();

bufferedOutputStream.close();//先關閉包裝流

fileOutputStream.close();

}

}

上述兩種寫法都沒有問題,我們已經知道bufferedOutputStream.close();會自動調用fileOutputStream.close();方法,那么這個方法是怎么執行的呢?我們又看看FileOutputStream的源碼:

public void close() throwsIOException {synchronized(closeLock) {if(closed) {return;

}

closed= true;

}

...

可以看出它采用同步鎖,而且使用了關閉標記,如果已經關閉了則不會再次操作,所以多次調用不會出現問題。

如果沒有看過參考文章,我可能就會斷下結論,關閉流不需要考慮順序。

我們看下下面的代碼(修改自參考文章):

importjava.io.BufferedWriter;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.OutputStreamWriter;public classIOTest {public static void main(String[] args) throwsIOException {

FileOutputStream fos= new FileOutputStream("c:\\a.txt");

OutputStreamWriter osw= new OutputStreamWriter(fos, "UTF-8");

BufferedWriter bw= newBufferedWriter(osw);

bw.write("java IO close test");//從內帶外順序順序會報異常

fos.close();

osw.close();

bw.close();

}

}

會拋出Stream closed的IO異常:

Exception in thread "main"java.io.IOException: Stream closed

at sun.nio.cs.StreamEncoder.ensureOpen(StreamEncoder.java:45)

at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:118)

at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207)

at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129)

at java.io.BufferedWriter.close(BufferedWriter.java:264)

at IOTest.main(IOTest.java:18)

而如果把bw.close();放在第一,其他順序任意,即修改成下面兩種:

bw.close();

osw.close();

fos.close();

bw.close();

fos.close();

osw.close();

都不會報錯,這是為什么呢,我們立即看看BufferedWriter的close源碼:

public void close() throwsIOException {synchronized(lock) {if (out == null) {return;

}try{

flushBuffer();

}finally{

out.close();

out= null;

cb= null;

}

}

}

里面調用了flushBuffer()方法,也是拋異常中的錯誤方法:

void flushBuffer() throwsIOException {synchronized(lock) {

ensureOpen();if (nextChar == 0)return;

out.write(cb,0, nextChar);

nextChar= 0;

}

}

可以看到很大的一行

out.write(cb, 0, nextChar);

這行如果在流關閉后執行就會拋IO異常,

有時候我們會寫成:

fos.close();

fos= null;

osw.close();

osw= null;

bw.close();

bw= null;

這樣也會拋異常,不過是由于flushBuffer()中ensureOpen()拋的,可從源碼中看出:

private void ensureOpen() throwsIOException {if (out == null)throw new IOException("Stream closed");

}void flushBuffer() throwsIOException {synchronized(lock) {

ensureOpen();if (nextChar == 0)return;

out.write(cb,0, nextChar);

nextChar= 0;

}

}

如何防止這種情況?

直接寫下面這種形式就可以:

bw.close();

bw= null;

結論:一個流上的close方法可以多次調用,理論上關閉流不需要考慮順序,但有時候關閉方法中調用了write等方法時會拋異常。

由上述的兩個結論可以得出下面的建議:

關閉流只需要關閉最外層的包裝流,其他流會自動調用關閉,這樣可以保證不會拋異常。如:

bw.close();

//下面三個無順序

osw = null;

fos= null;

bw= null;

注意的是,有些方法中close方法除了調用被包裝流的close方法外還會把包裝流置為null,方便JVM回收。bw.close()中的:

public void close() throwsIOException {synchronized(lock) {if (out == null) {return;

}try{

flushBuffer();

}finally{

out.close();

out= null;

cb= null;

}

}

}

finally中就有把out置為null的代碼,所以有時候不需要自己手動置為null。(個人建議還是寫一下,不差多少執行時間)

原文鏈接:https://blog.csdn.net/maxwell_nc/article/details/49151005

總結

以上是生活随笔為你收集整理的java关闭io流_Java IO流关闭问题的深入研究的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。