天天看点

6.缓冲字节输入流BufferedInputStream6.BufferedInputStream 缓冲输入字节流

6.BufferedInputStream 缓冲输入字节流

1.BufferedInputStream:

       通过使用FileInputStream我们可以知道,使用缓冲数组能提高读取效率。因此sun给我们提供了一个缓冲输入字节流对象,让我们可以更高效的读取文件。

2.输入字节流体系

- - - - | InputStream 输入字节流的基类,抽象类

- - - - - - - - - | FileInputStream 读取文件数据的输入字节流(直接从硬盘读取),每次读取一个字节

- - - - - - - - - | BufferedInputStream 缓冲输入字节流,它的出现主要是为了提高读取文件数据的效率。其实BufferedInputStream只不过是在内部维护了一个8192字节(8kb)的字节数组而已。

3.使用BufferedInputStream的步骤:

   1.找到目标文件

      File file = new File("E:\\aa\\a.txt");

   2.建立数据通道

      BufferedInputStream bufferedInputStream = new BufferedInputStream(newFileInputStream(file));

   3.读取数据

      int content = bufferedInputStream.read();// 借用的是FileInputStream的read()方法的读取文件数据的能力,所有缓冲字节流都不具备读写文件的功能。

   4.释放流资源

      bufferedInputStream.close();// (实际上关闭的是 FileInputStream的资源。)

4.关于 BufferedInputStream 的问题:

(1)为什么创建BufferedInputStream对象的时候,要传入FileInputStream对象?

   答:因为所有的缓冲字节流都不具备读写文件的能力。所以BufferedInputStream不具备读写文件的能力,不能直接从硬盘中读取文件中的数据。需要借助FileInputStream的read()的读取文件数据的能力来完成文件数据的读取操作。

(2)BufferedInputStream出现的目的是为了提高读取数据的效率,但是BufferedInputStream每次读取一个字节的数据,而FileInputStream也是每次读写一个字节的数据,那么BufferedInputStream的高效率从何而来呢?

   答:BufferedInputStream只不过是在类的内部维护了一个8192字节(8kb)的字节数组而已。

      从BufferedInputStream的源码看它的运行原理:

BufferedInputStream的源码:

public synchronized int read() throws IOException {

   if (pos >= count) {

      fill();

      if (pos >= count)

         return -1;

   }

   return getBufIfOpen()[pos++] & 0xff;

}

源码解读:

pos:当前已经读取到了第几个字节(指针作用)

count:本次读取了几个字节存储到了缓冲数组中。

getBufIfOpen():获取字节数组中的数据。

fill():填充。获取getBufIfOpen()获取到的字节数组中的数据。使用BufferedInputStream内部维护的数组去读取文件数据,每次最多读取8kb(8192字节)的数据进入缓冲数组。

通过源码可以得知BufferedInputStream缓冲字节输入流的运行原理:

   BufferedInputStream 是从字节数组(也就是内存中)读取数据的,它没有读写文件的能力。

    第一次读取时pos和count都是0,此时进入if内部调用 fill() 方法,fill() 维护了 getBufIfOpen() 方法读取的数据(每次最多8kb)。

    fill() 方法起到一个指针的作用,每读取完一个字节指针索引值+1,直到pos>=count,return -1读取完字节数组中的所有数据,然后pos指针清零,继续下一轮的读取操作,直到将文件中的所有数据都读取完成。

(3)当使用完流资源,要第一时间将流资源关闭,为什么只关闭BufferedInputStream的流资源,而不关闭FileInputStream的流资源?

   答:关闭BufferedInputStream的资源,实际上关闭的就是FileInputStream的资源,因为BufferedInputStream不具备读取文件的能力,所以不需要释放资源。而它读取文件的能力是借助的FileInputStream的read()方法,所以关闭的实际上是FIleInputStream的资源。

5.BufferedInputStream与FileInputStream的使用选取问题?

看个人习惯,总的来说,使用FileInputStream搭配数组的效率应该比BufferedInputStream的效率要高。

从以下几点可以分析出:

   1.执行流程:从BufferedInputStream的源码可以看出,每次读取字节都需要进行if判断,这就很影响工作效率了。

   2.程序员所需写的代码量:两种字节输入流使用时,所需的代码量是相同的。只不过FileInputStream需要自己去维护一个byte数组而BufferedInputStream却需要将FileInputStream传入它构建的对象中。

   3.维护数组:BufferedInputStream内部维护的数组是8kb(8192个字节),也就是1024*8个字节,是固定的。而程序员自己去维护数组的话,会更加灵活。

6.案例

public class Dome1 {
    /*
        3.使用BufferedInputStream的步骤:
            1.找到目标文件
            2.建立数据通道
            3.读取数据
            4.释放流资源
     */
    public static void main(String[] args) {
        // 1.找到目标文件
        File file = new File("E:\\aa\\bb\\a.txt");
        FileInputStream fileInputStream = null;
        BufferedInputStream bufferedInputStream = null;

        try {
            // 2.搭建数据通道
            // 疑问1:问什么在创建BufferedInputStream的时候,要传入FileInputStream? 因为BufferedInputStream(所有缓冲字节流)不具备读写文件的能力,需要借助FileInputStream的read()方法读取文件数据内容。
            fileInputStream = new FileInputStream(file);
            bufferedInputStream = new BufferedInputStream(fileInputStream);

            // 3.读取数据
            /*
                缓冲字节输入流的运行原理:BufferedInputStream只不过是在类的内部维护了一个8192字节(8kb)的字节数组而已。
                BufferedInputStream源码:
                    public synchronized int read() throws IOException {
                        if (pos >= count) {
                            fill();
                            if (pos >= count)
                                return -1;
                        }
                        return getBufIfOpen()[pos++] & 0xff;
                    }
                    pos:当前已经读取到了第几个字节(指针作用)
                    count:本次读取了几个字节存储到了缓冲数组中。
                    getBufIfOpen():获取字节数组中的数据。
                    fill():填充。获取getBufIfOpen()获取到的字节数组中的数据。使用BufferedInputStream内部维护的数组去读取文件数据,每次最多读取8kb(8192字节)的数据进入缓冲数组。

                通过源码可以得知BufferedInputStream缓冲字节输入流的运行原理:
                    BufferedInputStream是从字节数组(也就是内存中)读取数据的,
                    第一次读取时pos和count都是0,此时进入if内部调用fill()方法,fill()维护getBufIfOpen()方法一次性读取的最多8kb的数据。
                    fill()方法起到一个指针的作用,每读取完一个字节指针索引值+1,直到pos>=count,return -1读取完文件中的所有数据。
             */
            int content = 0;
            while ((content = bufferedInputStream.read()) != -1) {
                System.out.println((char) content);
            }
        } catch (FileNotFoundException e) {
            System.out.println("寻找目标文件失败...");
            throw new RuntimeException(e);// 将异常封装到运行时异常处理掉
        } catch (IOException e) {
            System.out.println("读取文件内容失败...");
            throw new RuntimeException(e);
        } finally {
            try {
                // 4.释放资源
                System.out.println("关闭流资源成功......");
                bufferedInputStream.close();//实际上释放的是FileInputStream的资源,因为BufferedInputStream不具备读写文件的能力,所以不能搭建与文件之间的通道,它借助的是FileInputStream的read()方法来读写文件的数据。
            } catch (IOException e) {
                System.out.println("关闭流资源失败......");
                throw new RuntimeException(e);
            }
        }
    }
}
           

总结:简单来说,BufferedInputStream读取文件的过程,是通过FileInputStream的read()方法,将硬盘中文件的数据内容读取到BufferedInputStream内部维护的字节数组中,此时数据存储到了内存中,BufferedInputStream的read()方法是从字节数组(也就是内存中)来读取数据的。这也就是为什么BufferedInputStream明明不具备读写文件的功能,却能读取文件中数据的原因。

继续阅读