深入理解:输入流read方法的底层运作原理,以及为什么缓存空间可以极大的提升读取文件的效率
- 一·FileInputStream类的read方法官方JDK解释如下图所示:可能文档说的太过官方,本人来阐述说明一下。
- 二·FileReader类都是继承实现的Reader基类的read方法,官方JDK解释如下图所示:可能文档说的太过官方,本人来阐述说明一下。
- 三·为什么缓存空间可以极大的提升IO流读写文件的效率,又是如何提升系统的整体性能呢?
- 四·注意事项:
- 1.缓存数组,又称“缓冲数组”
- 2.官方文档中“直到某些输入可用”的词语解释:直到利用同一个输入流对象再次调用该read方法
- 3.调用read(byte[] b)以及read( byte [] b , int off , int len)方法时,传入的缓存字节数组byte[]大小,可以随便设置长度,但长度不能小于1。
- 4.缓冲数组可以极大的提升IO流读写文件的效率,当很多缓存空间都发挥如此作用的时候,也就提升了系统的整体性能。
- 5.当read方法读取数据返回的是-1时,此时read方法虽然会停掉,但是输入流进程仍然没有关闭,必须执行close方法才能关闭流的进程。
- 6.其他输入流的read方法理解本质上与上文两种都差不多,类推就行
一·FileInputStream类的read方法官方JDK解释如下图所示:可能文档说的太过官方,本人来阐述说明一下。
1.read():
(1)当输入流对象调用这个方法时,一次调用只会从某个文件中读取一字节(也就是8位)的二进制数据,然后返回读取的一字节数据。
(2)执行完一次调用之后,该方法并不会立即停掉,而是会进入阻塞状态。进程阻塞就是进程会在后台挂起,即,占着cpu内存,却不执行任何任务,但这样可以加快启动与调用的速度。
一旦这样的进程过多就会很耗费计算机各种资源,所以每次我们读完文件数据之后,都必须关掉输入输出流的原因就是这么回事。
(3)直到利用“同一个输入流对象”再次调用它,那么该read方法就会被唤醒,它就会接着从上次停止的地方继续执行读取操作。
2.read(byte [] b ):开发中常用
(1)当输入流对象调用这个方法时,该方法底层会一字节一字节的读取数据,每读取到一字节数据就会自动填充到缓存数组byte[]中去(从数组偏移量0开始),
直到填满缓存数组,该read方法就会返回本次调用填充缓存数组的总字节数。
(2)执行完一次调用之后,该方法并不会立即停掉,而是会进入阻塞状态。进程阻塞就是进程会在后台挂起,即,占着cpu内存,却不执行任何任务,但这样可以加快启动与调用的速度。
一旦这样的进程过多就会很耗费计算机各种资源,所以每次我们读完文件数据之后,都必须关掉输入输出流的原因就是这么回事。
(3)一般循环调用该方法读取文件数据时,不到文件末尾,每次读取的总字节数都会与缓存数组长度相等。
也就是说倒数第三次以上读取的文件总字节数,都等于缓存数组长度;
但是倒数第二次读取的总字节数就不一定等于缓存数组的长度,因为文件未被读取的数据中未必有足够的数据去填充缓存数组;
最后一次读取返回的才是-1,表示读取文件数据截止。
(4)直到利用“同一个输入流对象”再次调用它,那么该read方法就会被唤醒,它就会接着从上次停止的地方继续执行读取操作。
(5)注意:若最后一次调用该方法去读取文件的数据不够填满缓存数组,那么则会返回实际填充缓存数组的总字节数并进入阻塞状态;此时,再次调用该read方法,返回的才是-1,表示文件末尾截止了!!!
3.read( byte [] b , int off , int len):
(1)当输入流对象调用这个方法时,该方法底层会一字节一字节的读取数据,每读取到一字节数据就会自动填充到缓存数组byte[]中去(从数组偏移量off开始),
一次方法调用中最多填充len字节数到缓存数组中,该read方法就会返回本次调用填充缓存数组的总字节数。
(2)执行完一次调用之后,该方法并不会立即停掉,而是会进入阻塞状态。进程阻塞就是进程会在后台挂起,即,占着cpu内存,却不执行任何任务,但这样可以加快启动与调用的速度。
一旦这样的进程过多就会很耗费计算机各种资源,所以每次我们读完文件数据之后,都必须关掉输入输出流的原因就是这么回事。
(3)直到利用“同一个输入流对象”再次调用它,那么该read方法就会被唤醒,它就会接着从上次停止的地方继续执行读取操作。
(4)如果off为负数,或者len为负数,也或者 len为大于 b.length - off 的数,这个方法运行时都会报错
二·FileReader类都是继承实现的Reader基类的read方法,官方JDK解释如下图所示:可能文档说的太过官方,本人来阐述说明一下。
1.read():
(1)当输入流对象调用这个方法时,一次调用只会从某个文件中读取一字符的二进制数据,然后返回读取的一字符数据。
注意:若字符是英文,则是读取一字节的数据;若字符是汉字,则是读取2字节的数据;返回的是二进制数据,显示在控制台会转换为int类型数据,
只要将这个int类型数据赋值给char类型数据再进行输出就可以成功转换为字符了。
(2)执行完一次调用之后,该方法并不会立即停掉,而是会进入阻塞状态。进程阻塞就是进程会在后台挂起,即,占着cpu内存,却不执行任何任务,但这样可以加快启动与调用的速度。
一旦这样的进程过多就会很耗费计算机各种资源,所以每次我们读完文件数据之后,都必须关掉输入输出流的原因就是这么回事。
(3)直到利用“同一个输入流对象”再次调用它,那么该read方法就会被唤醒,它就会接着从上次停止的地方继续执行读取操作。
2.read(char[] cbuf):开发中常用
(1)当输入流对象调用这个方法时,该方法底层会一字符一字符的读取数据,每读取到一字符数据就会自动填充到缓存数组char[]中去(从数组偏移量0开始),
直到填满缓存数组,该read方法就会返回本次调用填充缓存数组的总字符数。
(2)执行完一次调用之后,该方法并不会立即停掉,而是会进入阻塞状态。进程阻塞就是进程会在后台挂起,即,占着cpu内存,却不执行任何任务,但这样可以加快启动与调用的速度。
一旦这样的进程过多就会很耗费计算机各种资源,所以每次我们读完文件数据之后,都必须关掉输入输出流的原因就是这么回事。
(3)一般循环调用该方法读取文件数据时,不到文件末尾,每次读取的总字符数都会与缓存数组长度相等。
也就是说倒数第三次以上读取的文件总字符数,都等于缓存数组长度;
但是倒数第二次读取的总字符数就不一定等于缓存数组的长度,因为文件未被读取数据已经没了;最后一次读取返回的才是-1,表示读取文件数据截止。
(4)直到利用“同一个输入流对象”再次调用它,那么该read方法就会被唤醒,它就会接着从上次停止的地方继续执行读取操作。
(5)注意:若最后一次调用该方法去读取文件的数据不够填满缓存数组,那么则会返回实际填充缓存数组的总字符数并进入阻塞状态;此时,再次调用该read方法,返回的才是-1,表示文件末尾截止了!!!
3.read(char[] cbuf, int off, int len):
(1)当输入流对象调用这个方法时,该方法底层会一字符一字符的读取数据,每读取到一字符数据就会自动填充到缓存数组char[]中去(从数组偏移量off开始),
一次方法调用中最多填充len字符数到缓存数组中,该read方法就会返回本次调用填充缓存数组的总字符数。
(2)执行完一次调用之后,该方法并不会立即停掉,而是会进入阻塞状态。进程阻塞就是进程会在后台挂起,即,占着cpu内存,却不执行任何任务,但这样可以加快启动与调用的速度。
一旦这样的进程过多就会很耗费计算机各种资源,所以每次我们读完文件数据之后,都必须关掉输入输出流的原因就是这么回事。
(3)直到利用“同一个输入流对象”再次调用它,那么该read方法就会被唤醒,它就会接着从上次停止的地方继续执行读取操作。
(4)如果off为负数,或者len为负数,也或者 len为大于 b.length - off 的数,这个方法运行时都会报错
三·为什么缓存空间可以极大的提升IO流读写文件的效率,又是如何提升系统的整体性能呢?
1.前提共识:不需要修改原文件数据的操作就是输入流,需要修改某文件数据的操作就是输出流。
(1)从磁盘往cpu内存读取数据的速度为v1
(2)从cpu内存往程序里面读取数据的速度为v2
(3)从程序里面往cpu内存写数据的速度为v3
(4)从cpu内存往磁盘写数据为v4
结论:v2 = v3,v1 = v4,v2 >> v1,v3 >> v4