JavaIO流之字节流

IO的概述、分类、使用场景

IO流介绍

IO流的分类

按照数据的流向

按照数据类型来分

IO流的使用场景

字节流

写入数据

字节流抽象基类

字节输出流

使用字节输出流写数据的步骤

字节流写数据的三种方式

字节流写数据的两个小问题

关于字节流的异常处理

读取数据

字节流读多个字节

案例-文件复制

案例改进方案-小数组拷贝

小数组拷贝的原理分析


IO的概述、分类、使用场景

IO流介绍

IO:输入/输出(Input/Output)

流:是一种抽象概念,是对数据传输的总称.也就是说数据在设备间的传输称为流,流的本质是数据传输

IO流就是用来处理设备间数据传输问题的.常见的应用: 文件复制; 文件上传; 文件下载

IO的数据传输可以看作是一种数据流动,以内存为参照物,进行数据读写。

IO流的分类

按照数据的流向

  • 输入流:读数据
  • 输出流:写数据

按照数据类型来分

字节流

  • 字节输入流
  • 字节输出流

字符流

  • 字符输入流
  • 字符输出流

IO流的使用场景

如果操作的是纯文本文件,优先使用字符流

如果操作的是图片、视频、音频等二进制文件,优先使用字节流

如果不确定文件类型,优先使用字节流字节流万能的流。

字节流

写入数据

字节流抽象基类

InputStream:这个抽象类是表示字节输入流的所有类的超类

OutputStream:这个抽象类是表示字节输出流的所有类的超类

子类名特点:子类名称都是以其父类名作为子类名的后缀

字节输出流

FileOutputStream(String name):创建文件输出流以指定的名称写入文件

使用字节输出流写数据的步骤

1. 创建字节输出流对象(调用系统功能创建了文件,创建字节输出流对象,让字节输出流对象指向文件)

2. 调用字节输出流对象的写数据方法

3. 释放资源(关闭此文件输出流并释放与此流相关联的任何系统资源)

我们常用的是第一个第四个构造,但其实他们的意思是一样的,都是将路径地址传递给FileOutputStream。

源码如下

public FileOutputStream(String name) throws FileNotFoundException {
        this(name != null ? new File(name) : null, false);
}

如果传入的是字符串类型的,在代码底层也是会给他转换成File类型的对象。

实例代码

public class Demo01 {
    public static void main(String[] args) throws IOException {
        //1.创建字节输出流对象
      	/**
      		1.如果文件不存在,会帮我们创建
      		2.如果文件存在,会把文件清空
      	*/
        //2种最常用的构造方式
        FileOutputStream fos01 = new FileOutputStream("a.txt");
        FileOutputStream fos02 = new FileOutputStream(new File("a.txt"));
        
        //2.写数据
        fos01.write(98);
        //3.关闭此文件输出流并释放与此流相关联的任何系统资源
        fos01.close();
    }
}

上述代码使用了2种构造方法创建FileOutputStream对象。

字节流写数据的三种方式

方法名说明
void write(int b)将指定的字节写入此文件输出流 一次写一个字节数据
void write(byte[] b)将 b.length字节从指定的字节数组写入此文件输出流 一次写一个字节数组数据
void write(byte[] b, int off, int len)len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流 一次写一个字节数组的部分数据(off是第几个索引开始,len是写几个)

字节流写数据的两个小问题

  • 字节流写数据如何实现换行

    • windows:\r\n

    • linux:\n

    • mac:\r

这里可以使用getBytes()方法,得到一个操作系统默认的编码格式的字节数组

  • 字节流写数据如何实现追加写入

    • public FileOutputStream(String name,boolean append)  第3个构造

    • 创建文件输出流以指定的名称写入文件。如果第二个参数为true ,则字节将写入文件的末尾而不是开头(追加)

public class Demo02 {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("a.txt",true);
        for (int i = 0; i < 10; i++) {
            fos.write("hello".getBytes());
            fos.write("\r\n".getBytes());
        }
        fos.close();
    }
}

关于字节流的异常处理

try{
    可能出现异常的代码;
}catch(异常类名 变量名){
    异常的处理代码;
}finally{
    执行所有清除操作;
}

finally特点

  • 被finally控制的语句一定会执行,除非JVM退出

Coding

public class FileOutputStreamDemo04 {
    public static void main(String[] args) {
        
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream("a.txt");
            fos.write("hello".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

读取数据

  • 字节输入流

    • FileInputStream(String name):通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的路径名name命名

  • 字节输入流读取数据的步骤

    • 创建字节输入流对象

    • 调用字节输入流对象的读数据方法

    • 释放资源

基本样例

public class FileInputStreamDemo01 {
    public static void main(String[] args) throws IOException {
        
        FileInputStream fis = new FileInputStream("a.txt");
        int read = fis.read();
        System.out.println((char)read);
        fis.close();
    }
}

字节流读多个字节

public class FileInputStreamDemo01 {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("myByteStream\\fos.txt");
        int by;

        // -1 表示文件读到了结束
        // 不同操作系统可能会有不同!
        while ((by=fis.read())!=-1) {
            System.out.print((char)by);
        }

        fis.close();
    }
}

案例-文件复制

  • 案例需求

    把“E:\itcast\窗里窗外.txt”复制到模块目录下的“窗里窗外.txt” (文件可以是任意文件)

  • 实现步骤

    • 复制文本文件,其实就把文本文件的内容从一个文件中读取出来(数据源),然后写入到另一个文件中(目的地)

    • 数据源:

      E:\itcast\窗里窗外.txt --- 读数据 --- InputStream --- FileInputStream

    • 目的地:

      myByteStream\窗里窗外.txt --- 写数据 --- OutputStream --- FileOutputStream

Coding

public class CopyTxtDemo {
    public static void main(String[] args) throws IOException {
        //根据数据源创建字节输入流对象
        FileInputStream fis = new FileInputStream("E:\\itcast\\窗里窗外.txt");
        //根据目的地创建字节输出流对象
        FileOutputStream fos = new FileOutputStream("myByteStream\\窗里窗外.txt");

        //读写数据,复制文本文件(一次读取一个字节,一次写入一个字节)
        int by;
        while ((by=fis.read())!=-1) {
            fos.write(by);
        }

        //释放资源
        fos.close();
        fis.close();
    }
}

案例改进方案-小数组拷贝

上述代码存在的效率问题,每次只能读取一个字节,一次一次的传递导致效率十分低下! 

措施 

 

 Coding

package IO流.FileOutputStream类;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Demo03 {
    public static void main(String[] args) throws IOException, IOException {
        //根据数据源创建字节输入流对象
        FileInputStream fis = new FileInputStream("E:\\itcast\\窗里窗外.txt");
        //根据目的地创建字节输出流对象
        FileOutputStream fos = new FileOutputStream("myByteStream\\窗里窗外.txt");

        byte [] bytes = new byte[1024];
        int len;
        while ((len = fis.read(bytes)) != -1) {
            fos.write(bytes,0,len);
        }

        fos.close();
        fis.close();
    }
}

小数组拷贝的原理分析

我们可以举一个例子来说明,假设byte数组的大小是2,数据源有abcde,则每次读入两个字符,这里第一次读入的是ab

 第二次读入是cd,将覆盖字符数组原来的值。

最后一次,因为只剩下一个e,所以读入后字符数组中的值为ed,len长度为1,但是不影响,在write(bytes,0,len),表示输出长度为len = 1 的。

posted @ 2022-01-21 15:44  金鳞踏雨  阅读(26)  评论(0)    收藏  举报  来源