Java IO包装流如何关闭?
关闭流的实例在下面,往后拖就OK了
问题:
(1)JAVA的IO流使用了装饰模式,关闭最外面的流的时候会自动调用被包装的流的close()方吗?
(2)如果按顺序关闭流,是从内层流到外层流关闭还是从外层到内存关闭?
问题(1)解释:
如下例子代码:
FileInputStream is = new FileInputStream(".");
BufferedInputStream bis = new BufferedInputStream(is);
bis.close();
从设计模式上看:
java.io.BufferedInputStream是java.io.InputStream的装饰类。
BufferedInputStream装饰一个 InputStream 使之具有缓冲功能,is要关闭只需要调用最终被装饰出的对象的 close()方法即可,因为它最终会调用真正数据源对象的 close()方法。
BufferedInputStream的close方法中对InputStream进行了关闭,下面是jdk中附带的源代码:
java.io.BufferedInputStream的api:
close
public void close()throws IOException 关闭此输入流并释放与该流关联的所有系统资源。
因此,可以只调用外层流的close方法关闭其装饰的内层流,验证例子:
public static void main(String[] args) throws Exception {
FileOutputStream fos = new FileOutputStream("d:\\a.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
BufferedWriter bw = new BufferedWriter(osw);
bw.write("java IO close test");
bw.close();
}
验证ok
问题(2)解释:如果不想使用(1)方式关闭流,可以逐个关闭流(可能大家比较习惯吧)
如下例子:
public static void main(String[] args) throws Exception {
FileOutputStream fos = new FileOutputStream("d:\\a.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
BufferedWriter bw = new BufferedWriter(osw);
bw.write("java IO close test");
//从内带外顺序顺序会报异常
fos.close();
osw.close();
bw.close();
}
报出异常:
Exception in thread "main" java.io.IOException: Stream closed
at sun.nio.cs.StreamEncoder.ensureOpen(StreamEncoder.java:26)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:99)
at java.io.OutputStreamWriter.write(OutputStreamWriter.java:190)
at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:111)
at java.io.BufferedWriter.close(BufferedWriter.java:246)
at com.my.test.QQ.main(QQ.java:22)
如下例子:
public static void main(String[] args) throws Exception {
FileOutputStream fos = new FileOutputStream("d:\\a.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
BufferedWriter bw = new BufferedWriter(osw);
bw.write("java IO close test");
// 从外到内顺序关闭ok
bw.close();
osw.close();
fos.close();
}
验证ok
一般情况下是:先打开的后关闭,后打开的先关闭
另一种情况:看依赖关系,如果流a依赖流b,应该先关闭流a,再关闭流b
例如处理流a依赖节点流b,应该先关闭处理流a,再关闭节点流b
当然完全可以只关闭处理流,不用关闭节点流。处理流关闭的时候,会调用其处理的节点流的关闭方法
如果将节点流关闭以后再关闭处理流,会抛出IO异常;
Java之关闭流
我们深知在操作Java流对象后要将流关闭,但往往事情不尽人意,大致有以下几种不能一定将流关闭的写法:
1.在try中关流,而没在finally中关流
1. try {
2. new FileOutputStream("");
3. // ...操作流代码
4. out.close();
5. } catch (Exception e) {
6. e.printStackTrac
- e();
- }
正确写法:
1. OutputStream out = null;
2. try {
3. new FileOutputStream("");
4. // ...操作流代码
5. } catch (Exception e) {
6. e.printStackTrace();
7. } finally {
8. try {
9. if (out != null) {
10. out.close();
11. }
12. catch (Exception e) {
13. e.printStackTrace();
14. }
15. }
2.在关闭多个流时因为嫌麻烦将所有关流的代码丢到一个try中
1. OutputStream out = null;
2. OutputStream out2 = null;
3. try {
4. new FileOutputStream("");
5. new FileOutputStream("");
6. // ...操作流代码
7. } catch (Exception e) {
8. e.printStackTrace();
9. } finally {
10. try {
11. if (out != null) {
12. // 如果此处出现异常,则out2流没有被关闭
13. }
14. if (out2 != null) {
15. out2.close();
16. }
17. catch (Exception e) {
18. e.printStackTrace();
19. }
20. }
正确写法:
1. OutputStream out = null;
2. OutputStream out2 = null;
3. try {
4. new FileOutputStream("");
5. new FileOutputStream("");
6. // ...操作流代码
7. } catch (Exception e) {
8. e.printStackTrace();
9. } finally {
10. try {
11. if (out != null) {
12. // 如果此处出现异常,则out2流也会被关闭
13. }
14. catch (Exception e) {
15. e.printStackTrace();
16. }
17. try {
18. if (out2 != null) {
19. out2.close();
20. }
21. catch (Exception e) {
22. e.printStackTrace();
23. }
24. }
3.在循环中创建流,在循环外关闭,导致关闭的是最后一个流
1. OutputStream out = null;
2. try {
3. for (int i = 0; i < 10; i++) {
4. new FileOutputStream("");
5. // ...操作流代码
6. }
7. } catch (Exception e) {
8. e.printStackTrace();
9. } finally {
10. try {
11. if (out != null) {
12. out.close();
13. }
14. catch (Exception e) {
15. e.printStackTrace();
16. }
17. }
正确写法:
1. for (int i = 0; i < 10; i++) {
2. null;
3. try {
4. new FileOutputStream("");
5. // ...操作流代码
6. catch (Exception e) {
7. e.printStackTrace();
8. finally {
9. try {
10. if (out != null) {
11. out.close();
12. }
13. catch (Exception e) {
14. e.printStackTrace();
15. }
16. }
17. }
PS:在Java7中,关闭流这种繁琐的事情再也不用我们自己敲代码了:
1. try (OutputStream out = new FileOutputStream("")){
2. // ...操作流代码
3. } catch (Exception e) {
4. e.printStackTrace();
5. }
只要实现的自动关闭接口(Closeable)的类都可以在try结构体上定义,java会自动帮我们关闭,及时在发生异常的情况下也会。可以在try结构体上定义多个,用分号隔开即可,如:
1. try (OutputStream out = new FileOutputStream("");OutputStream out2 = new FileOutputStream("")){
2. // ...操作流代码
3. } catch (Exception e) {
4. throw e;
5. }