在创建一个流的时候,就比如说FileIntputStream,我们在读取文件信息的时候,文件的指针会随着文件的读取从文件头一直往文件尾移动,当我们把文件中的数据都读完了,文件的指针也就到达了文件尾部,你若是再使用这个流去读取文件,显然你已经无法在读取前面的信息了。

如下图所示

java FileOutputStream 需要关闭 fileinputstream不关闭_缓存

下面是打印信息,显然没有进入第二个循环中,只打印了一个空行

java FileOutputStream 需要关闭 fileinputstream不关闭_读取文件_02

 

 

当然如果你在重新读取之前你把流关闭,这能将文件的指针重新指向文件头,这也就能重新读取文件的信息了。

如图所示

java FileOutputStream 需要关闭 fileinputstream不关闭_intellij-idea_03

 

java FileOutputStream 需要关闭 fileinputstream不关闭_java_04

这显然是我们所期望的。

但是这并不能适用于任何情况,就比如说我们在使用Buffered和PrintWriter时,这两个流其实是包装流,也可以说是高级流,在他们被创建的时候,实际上会在底层创建一个原始流,就说是底层流吧,我们在关闭Buffered和PrintWriter时,也将会把底层流给关闭,若是底层正在进行数据的读与写操作,这很可能会将数据丢失, 显然如果我们把底层流关闭,也将会出异常,原始流都没有了,包装流还有什么用呢。

如下图所示

java FileOutputStream 需要关闭 fileinputstream不关闭_java_05

 

再考虑上面的,这种方法显然已经行不通了,这就需要我们去考虑其他路径了我们在使用BufferedInputStream是可以发现这个类里面的方法有一个是markSupported()这个方法决定是否这个类可以标记文件

我们看如下

java FileOutputStream 需要关闭 fileinputstream不关闭_intellij-idea_06

 如果可以标记则就返回true,不能就返回false,上图三方法是需要调用的三方法,mark(int reaflimit)是标记文件的位置,里面的参数意思是:在标记位置变无效之前所能读的字节的最大极限,reset()方法可以在有效范围内回到文件的标记位置。

我们看下面的示例

java FileOutputStream 需要关闭 fileinputstream不关闭_intellij-idea_07

java FileOutputStream 需要关闭 fileinputstream不关闭_读取文件_08

 

 你会发现好神奇,竟然能打印出来,你会发现我给Mark()传的参数是21,而文件里的数据也是而是一个字节,这刚刚好,根据我上面的说明,这个reset()是可以返回文件指针的,但是当我将参数传为0是,这也能打印出来

如下图所示

java FileOutputStream 需要关闭 fileinputstream不关闭_读取文件_09

 

java FileOutputStream 需要关闭 fileinputstream不关闭_java_10

 这又很神奇吧,好像这个readlimit参数没有任何用处,实际上并不完全对,事实上,mark 在 Java 中的实现是和缓冲区相关的。只要缓冲区够大,mark 后读取的数据没有超出缓冲区的大小,mark 标记就不会失效,但是如果缓存区域大小很小,当区域占满了数据,则缓存区域将会更新,这时候的缓存区域将会被重置,里面的mark也将会消失,因此,mark 后读取多少字节才失效,并不完全由 readlimit 参数确定,也和 BufferedInputStream 类的缓冲区大小有关,只有超过了缓冲区域的大小mark才会失效,甚至可以认为这只和缓存区域的大小有关,区域越大,我能反复读取文件的余地也就越大,反之区域越小,mark有效的区域也就越小。

在BufferedInputStream类中有两个成员属性,关于缓冲区域大小的,可供参考,如下图

java FileOutputStream 需要关闭 fileinputstream不关闭_读取文件_11