目录
- 一、为什么要关闭流?
- 二、close方法和flush方法
- 1.使用close方法
- 2.使用flush方法
- 三、流按指向分类
- 四、不用关闭的流
一、为什么要关闭流?
涉及到对外部资源的读写操作,包括网络、硬盘等等的I/O流,如果在使用完毕之后不关闭,会导致资源泄漏以及可能会引起文件锁定等问题。因此,需要在使用完毕之后关闭流。
关闭流是一种资源释放机制,意味着在使用完毕之后归还系统的内存、CPU或者网络等资源,避免资源长时间占用。常见的关闭流的方法是调用close()方法,该方法会将相关的资源释放,可以有效避免导致资源泄漏的问题。
需要注意的是,关闭流的时机非常重要,过早关闭可能会影响正常操作,而过晚关闭则可能导致资源泄漏。一般来说,使用完毕之后应该及时关闭流。在Java 7之后引入了try-with-resources
语法,可以在语法层面上自动关闭流,这是一种推荐的用法:
/* 读取文件 */
File file = new File("opsLiya.json");
try (FileInputStream fileInputStream = new FileInputStream(file)) {
/* 操作 */
}catch (IOException e){
/* 异常处理 */
}
当然也可以使用传统的finally代码块关闭流:
InputStream inputStream = null;
try {
inputStream = new FileInputStream("opsLiya.txt");
/* 操作 */
} catch (IOException e) {
/* 异常处理 */
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
/* 异常处理 */
}
}
}
二、close方法和flush方法
1.使用close方法
当我们使用输入流的时候,如FileInputStream
,对流进行关闭时,直接调用close方法即可。
close方法的底层如下:
这个close0方法的底层是一个native方法(本地方法)
此方法进行具体的关闭操作。
2.使用flush方法
当我们使用输出流的时候(即写入数据到文件或者网络中),如BufferedOutputStream
,对流进行关闭时,需要先调用flush方法再调用close方法。
我们进入到BufferedOutputStream
的flush方法的源码可以看到:
方法注释大概的意思是:刷新此缓冲输出流。这将强制将任何缓冲的输出字节写入底层输出流。
也就是说,在关闭流前调用flush方法,会将缓存中的数据强行刷新到输出目标中,避免数据丢失。
三、流按指向分类
Java中的流在指向上可以分为两大类,分别是用于读写内存的流和用于读写外部资源(文件、网络等)的流。
比如,用于读写内存的流又可以根据操作对象分为两类,如下:
- 操作对象是byte数组:
- ByteArrayInputStream
- ByteArrayOutputStream
- 操作对象是字符串:
- StringReader
- StringWriter
而用于读写外部资源的流,有如下这些:
- FileInputStream和 FileOutputStream:用于字节流读写文件;
- FileReader和FileWriter:用于字符流读写文件;
- BufferedInputStream和BufferedOutputStream:用于缓存读写字节流提升IO性能;
- BufferedReader和BufferedWriter:用于缓存读写字符流提升IO性能;
- DataInputStream和DataOutputStream:可以用于读写整数、浮点数等基本类型的字节流;
- ObjectInputStream和ObjectOutputStream:用于读写Java对象的字节流;
- Socket和ServerSocket:用于网络数据传输;
- HttpURLConnection:用于HTTP请求等。
四、不用关闭的流
对于Java中的ByteArrayInputStream
和ByteArrayOutputStream
,它们都是在内存中进行读写操作,不需要涉及到底层的外部资源(如文件、网络等等),因此在使用完毕后不一定需要显式地调用close方法去关闭。它们占用的内存将会被JVM自动回收。
我们可以去到ByteArrayInputStream
的close方法实现是一个空方法,如下:
当然,我们也可以手动释放它们占用的内存——使用try-with-resources
语法:
byte[] data = new byte[]{1, 2, 3, 4, 5};
try (ByteArrayInputStream bis = new ByteArrayInputStream(data);
ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
/* 操作 */
} catch (IOException e) {
/* 异常处理 */
}
注意:虽然它的close方法是空实现,但是我们为了保证代码的可读性和健壮性,仍然应该在使用完毕后及时关闭它们。