Java之资源关闭
Java之资源关闭
查看之前写了一个FileService.java的服务,在创建了流之后,没有关闭流,在测试的时候发现没有问题,是因为资源没有被另外引用。
当一直打开文件,并且不关闭的时候,会出现这样的异常:Too many open files in system,是指的系统级的文件句柄。可以理解为我们建立的OutputStream是先与系统的文件句柄连接,通过他才能操作文件。而系统的文件句柄资源是有限的。当我们不关闭流,那这个文件句柄就一直占用着,当“别人”再想用时就没有资源了,从而报出这样的异常。
传统方式的关闭文件流
1 | /** |
新方式的关闭文件流
1 | /** |
为什么要手动关闭文件流?
垃圾回收(GC)的特点
- 垃圾回收机制只负责回收堆内存资源,不会回收任务物理资源
- 程序无法精确控制垃圾回收动作的具体发生时间
- 在垃圾回收之前,总会先调用它的finalize方法
常见需手动释放的物理资源
- 文件/流资源
- 套接字资源
- 数据库连接资源
物理资源可以不手动释放吗?
- 资源被长时间无效占用
- 超过最大限制后,将无资源可用
- 导致系统无法正常运行
实战案例:文件拷贝(传统方式关闭流资源)
目的:Java7前,实现利用基础IO流完成文件拷贝功能。
实现步骤:
- 输入输出流的创建
- 文件的复制
- 流资源的关闭
代码实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61package com.java.example.resource;
import org.testng.annotations.Test;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* JDK7之前的文件拷贝功能
*
* @author jingLv
* @date 2020/10/30
*/
public class FileCopyTest {
public void copyFile() {
//1 .创建输入输出流
// 定义输入路径和输出路径
String originalUrl = "源文件路径";
String targetUrl = "拷贝文件路径";
// 声明文件输入流,文件输出流
FileInputStream originalFileInputStream = null;
FileOutputStream targetFileOutputStream = null;
try {
// 实例化文件流对象
originalFileInputStream = new FileInputStream(originalUrl);
targetFileOutputStream = new FileOutputStream(targetUrl);
//2. 执行文件拷贝,读取文件内容,写入到另一个文件中
// 读取的字节信息
int content;
// 迭代,读取/写入字节
while ((content = originalFileInputStream.read()) != -1) {
targetFileOutputStream.write(content);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//3. 关闭文件流资源
if (targetFileOutputStream != null) {
try {
targetFileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (originalFileInputStream != null) {
try {
originalFileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
实战案例:文件拷贝(TWR方式关闭流资源)
目的:Java7之后,实现利用基础IO流完成文件拷贝功能
实现步骤:
- 输入输出流的创建
- 文件的复制
注:这种方式不用显示的在关闭流了
代码实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43package com.java.example.resource;
import org.testng.annotations.Test;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* 基于JDK7之后,实现正确关闭流资源方法
* try - with - resource
*
* @author jingLv
* @date 2020/10/30
*/
public class NewFileCopyTest {
public void copyFile() {
//1 .创建输入输出流
// 定义输入路径和输出路径
String originalUrl = "源文件路径";
String targetUrl = "拷贝文件路径";
// 初始化输入/输出对象
try (
FileInputStream originalFileInputStream = new FileInputStream(originalUrl);
FileOutputStream targetFileOutputStream = new FileOutputStream(targetUrl);
) {
//2. 执行文件拷贝,读取文件内容,写入到另一个文件中
// 读取的字节信息
int content;
// 迭代,读取/写入字节
while ((content = originalFileInputStream.read()) != -1) {
targetFileOutputStream.write(content);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
try-with-resource简介
- Java7引入新特性
- 优雅关闭资源
- 一种Java语法糖
实战案例:源码分析
查看编译后源码,分析内部原理。
1 | // |
try-with-resource使用
- 多资源自动关闭
- 实现AutoCloseable接口
- 避免异常屏蔽
资源关闭顺序问题
先开后关原则
从外到内原则
底层资源单独声明原则
资源关闭特殊情况
- 资源对象被return的情况下,由调用方关闭
- ByteArrayInputStream等不需要检查关闭的资源对象
- 使用Socket获取的InputStream和OutputStream对象不需要关闭
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Jing's Blog!