字节流

概述

计算机中任何数据(文本、图片、视频、音乐等)都是以二进制(字节)形式存储的。JDK中所有字节输入流继承自抽象类InputStream,所有字节输出流继承自抽象类OutputStream。它们是字节流的顶级父类。

字节流体系结构

InputStream和OutStream这两个虽然提供了一系列和读写有关的方法,但是这两个类是抽象类,不能被实例化。因此,针对不同功能,InputStream和OutputStream提供不同的子类,

形成的体系结构如下:

FileOutputStream

操作文件的字节输出流,专门用于把数据写入文件。

通过FileOutputStream将数据输出到文件内,案例代码如下:

        //创建FileOutputStream对象
        FileOutputStream fs = new FileOutputStream("d:\\临时文件夹\\测试\\1.txt");

        //使用write(int b)将数据写出
        fs.write(65);
        fs.close();
        System.out.println("执行完毕");

运行结果展示:

上述代码展示的是一次写出一个字节的情况,下面我们更改一段代码,将一次写出一组字节:

        //创建FileOutputStream对象
        FileOutputStream fs = new FileOutputStream("d:\\临时文件夹\\测试\\1.txt");

        byte[] bytes = {65,66,67,68};
        //使用write(bytes[] b)将数据写出
        fs.write(bytes);
        fs.close();
        System.out.println("执行完毕");

运行结果展示:

字符流在每次输入前都会清空,如果不想清空,可以在创建FileOutputStream对象的构造方法后传入true,表示追加。

进入追加模式后,不会清空之前已有的内容,而是再原先的数据后继续输出。

我们也可以把字符串转为bytes[]数组,传入write(byte[] b)方法中输出,代码如下:

        //创建FileOutputStream对象
        FileOutputStream fs = new FileOutputStream("d:\\临时文件夹\\测试\\1.txt");

        //使用getBytes()方法将String类型数据转为byte类型数组
        byte[] bytes = "你好".getBytes();
        //使用write(bytes[] b)将数据写出
        fs.write(bytes);
        fs.close();
        System.out.println("执行完毕");

运行结果展示:

也可以通过write(byte[] b,int off,int len)对输出字节的开始索引和长度设置,代码如下:

        //创建FileOutputStream对象
        FileOutputStream fs = new FileOutputStream("d:\\临时文件夹\\测试\\1.txt");

        //使用getBytes()方法将String类型数据转为byte类型数组
        byte[] bytes = "A".getBytes();
        //使用write(bytes[] b)将数据写出
        fs.write(bytes,0,1);
        fs.close();
        System.out.println("执行完毕");

运行结果展示:


FileInputStream

FileInputStream是InputStream的子类,它是操作文件的字节输入流,专门用于读取文件中的数据。由于文件中读取数据是重复操作,因此需要通过循环语句实现数据的持续读取。

下面通过一个案例简单认识一下FileInputStream:

        FileInputStream fis = new FileInputStream("d:\\临时文件夹\\测试\\1.txt");

        int i = fis.read();

        System.out.println((char) i);

        int i2 = fis.read();

        System.out.println((char) i2);

        fis.close();

运行结果如下:

A
B

通过上述案例,我们可以看出read()方法每此可以读取一个字节。

我们可以设想,

如果使用循环,可以持续读取数据

接下来我们使用循环读取,代码如下:

        FileInputStream fis = new FileInputStream("d:\\临时文件夹\\测试\\1.txt");

        while (true) {
            int i = fis.read();
            System.out.println(i);
        }

运行结果如下:

65
66
67
-1
-1
-1
-1
-1
-1

当文件中数据读取完成后,继续向后读取每次会返回-1。

在源代码中加入条件判断即可。当返回-1时退出循环。代码如下:

    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("d:\\临时文件夹\\测试\\1.txt");

        while (true) {
            int i = fis.read();
            if (i == -1){
                break;
            }
            System.out.println(i);
        }
        fis.close();
    }

运行结果如下:

65
66
67

下面我们来看一下read(byte[] b)方法的使用注意事项,代码如下:

        FileInputStream fis = new FileInputStream("d:\\临时文件夹\\测试\\1.txt");

        //定义长度为10的byte数组
        byte[] bytes = new byte[10];

        //read(bytes[] b)读取字节保存在b中,返回读取的字节数
        fis.read(bytes);
        System.out.println(new String(bytes));

        fis.read(bytes);
        System.out.println(new String(bytes));

        fis.read(bytes);
        System.out.println(new String(bytes));

        fis.close();

运行结果如下:

ABCDEFGHIJ
KLMNOPQRST
UVWXYZQRST

之所以出现第3行结果的情况,

因为读取剩下7个字节的内容,覆盖原先前7个字节内容,最后3给字节没有覆盖。

为了解决这样的情况,

可以使用构造方法String(byte[] b,off,len),从off下标开始,len个长度的数组b转为String类型数据。

下面代码来看更改后的结果:

        FileInputStream fis = new FileInputStream("d:\\临时文件夹\\测试\\1.txt");

        //定义长度为10的byte数组
        byte[] bytes = new byte[10];

        //read(bytes[] b)读取字节保存在b中,返回读取的字节数
        int len = fis.read(bytes);
        System.out.println(new String(bytes,0,len));

        len = fis.read(bytes);
        System.out.println(new String(bytes,0,len));

        len = fis.read(bytes);
        System.out.println(new String(bytes,0,len));

        fis.close();

运行结果如下:

ABCDEFGHIJ
KLMNOPQRST
UVWXYZ

定义变量len保存每次读取的长度,通过String构造方法截取字节数组中len个字节,

这样就可以避免覆盖重复发生。

我们在最后一行添加如下代码,注意此时文件中的数据已经全部读完:

        len = fis.read(bytes);
        System.out.println(len);

控制台打印输出:

-1

也就是说,当读取完所有字节后,返回的读取个数为-1。我们可以利用这个特点将它作为退出循环的条件。
代码如下:

        FileInputStream fis = new FileInputStream("d:\\临时文件夹\\测试\\1.txt");

        //定义长度为10的byte数组
        byte[] bytes = new byte[10];

        int len = 0;
        while (true){
            len = fis.read(bytes);
            if (len == -1) {
                break;
            }
            System.out.println(new String(bytes,0,len));
        }
        fis.close();

运行结果如下:

ABCDEFGHIJ
KLMNOPQRST
UVWXYZ
posted on 2021-10-18 22:10  技术小伙伴  阅读(460)  评论(0)    收藏  举报