13 IO流:字节流、字符流、缓冲流、文件复制(字节/字符/缓冲区)、字符转换流、打印流、IO框架(黑马Java视频笔记)

在这里插入图片描述

IO流 >> 读写数据的方案

  • 用于数据的读写(文件中的数据、网络中的数据…)

1. 认识IO流

  • I:Input,输入流,负责把数据读到内存中去
  • O:Output,输出流,负责写数据
1)IO流的分类

在这里插入图片描述

2)IO流的体系
  • 字节输入流 InputStream(读字节数据)
  • 字节输出流 Output Stream(写字节数据)
  • 字符输入流 Reader(读字符数据)
  • 字符输出流 Writer(写字符数据)

在这里插入图片描述

2. 文件字节输入流

💡以内存为基准,把磁盘文件中的数据以字节的形式读入到内存中去

2.1 创建文件字节流对象
File file = new File("F:/Users/Typora/input.txt");
InputStream ffis = null;
InputStream fis = null;

try {
    // 方式一:
    ffis = new FileInputStream(file);
    // 方式二:
    fis = new FileInputStream("F:/Users/Typora/input.txt");
} catch (FileNotFoundException e) {
    e.printStackTrace();
}

🤔在try-catch中创建文件字节流对象,其变量为局部变量,外部不可用的 >>> 先在try-catch外创建空的字节流对象,然后在try-catch中复制

2.2 读取文件
1)使用read()方法一个一个字节的读取
// 2、使用FileInputStream字节输入流管道中的read方法读取文件字节数组到内存中
// 定义一个变量记住每次读取的一个字节
int b;
while ((b = fis.read()) != -1) {
    System.out.print((char) b);
}

⚠️一次只读取一个字节,对于纯英文合适,有多字节字符就不合适了

2)使用字节数组读取数据:byte[]
// 定义一个字节数组,用来装读取到的字节数组。
// 重新创建一个文件字节输入流管道与源文件接通:上面字节读取的已经读完了
fis = new FileInputStream("F:/Users/Typora/input.txt");    

byte[] buffer = new byte[1024];
// 定义一个变量记录每次读取到的字节数组长度。
int len;
while((len = fis.read(buffer))!=-1){
    System.out.println(new String(buffer,0,len));      
    // 把字节数组按照一定的编码格式,按照一定的格式,输出到控制台,默认UTF-8
}

💡当数组的容量很小时,可能因只读取了一个多字节字符的一部分,从而导致解码后出现乱码

3)使用字节流读取中文,如何保证输出不乱码,怎么解决?
  • 小文件:一次读完全部字节

    • readAllBytes[]
  • 如果文件过大,创建的字节数组也会过大,可能引起内存溢出

💡读取文本适合用字符流,字节流适合做数据的转移,比如文件赋值

3. 文件字节输出流

  • 以字节为基准,把内存中的数据以字节的形式写出到文件中去

3.1 创建输出流
// 1、创建FileOutputStream对象,指定写入的目的地
OutputStream fos = null;
try {
    fos = new FileOutputStream("F:/Users/Typora/output.txt"); // true表示追加内容,false表示覆盖内容
    //  fos = new FileOutputStream("F:/Users/Typora/output.txt" , true); // true表示追加内容,false表示覆盖内容
} catch (FileNotFoundException e) {
    e.printStackTrace();
}
3.2 使用write()写数据
//2、使用FileOutputStream对象中的方法write,把数据写入到目的地中
fos.write('a');
fos.write(65);
fos.write('\n');    // 换行
// 写一个字符串
byte[] bytes = "我爱你中国666".getBytes(StandardCharsets.UTF_8);  // getBytes()获取编码, 使用UTF-8编码
fos.write(bytes);
fos.write('\n');    // 换行
// 写字符串的部分
fos.write(bytes, 0, 3);

//刷新
fos.flush();

4. 输入流和输出流用完后都要关掉流

💡使用try-catch-finally资源释放方案会自动关闭流,释放资源

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

5. 文件复制 – 字节流

public static void main(String[] args) {
    // 目标:使用字节流完成文件的复制操作
    // 源文件:F:/Users/Typora/input.txt
    // 目标文件:F:/Users/Typora/output.txt(目标文件要带上文件名,无法自动生成文件名)
    String srcPath = "F:/Users/Typora/input.txt";
    String destPath = "F:/Users/Typora/output.txt";

    copyFile(srcPath, destPath);
}

// 复制文件
public static void copyFile(String srcPath, String destPath) {
    // 1、创建一个文件字节输入流管道与源文件接通,一个文件字节输出流管道与目标文件接通
    try (
            InputStream fis = new FileInputStream(srcPath);
            FileOutputStream fos = new FileOutputStream(destPath);
    ) {
        // 2、读取一个字节数组,写入一个字节数组,循环读取,循环写入
        byte[] buffer = new byte[1024];
        int len;
        while ((len = fis.read(buffer)) != -1) {
            fos.write(buffer, 0, len);  // 写入一个字节数组,从数组的哪个索引开始读,读几个字节
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println("复制完成!");
}
资源释放方案:
1)try - catch - finally
try{

}catch(Exception e){
	e.printStackTrace();
}finally{

}
  • finally代码区:无论try中的程序是否正常执行,最后都会执行finally区,除非JVM终止。

💡一般用于程序执行完成后进行资源的释放操作 >>> 但是有点臃肿,每一个流都要手写代码关闭

2)try - with - resource
try(定义资源1;定义资源2;....){
	可能出现异常的代码;
}catch(异常类名 变量名){
	异常的处理代码;
}

💡资源使用完毕后,会自动调用其close() 方法,完成对资源的释放!

  • try()中只能放置资源,否则报错
  • 资源一般是指最终实现了AutoCloseable接口

6. 字符流FileReader - FileWriter

6.1 字符输入流FileReader
1)认识
  • 以内存为基准,把文件中的数据以字符的形式读入到内存中

2)FileReader读取步骤

① 创建字符输入流 char[]

② 通过read方法获取文件内容

public static void main(String[] args) {
    // 目标:掌握文件字符输入流读取字符内容到程序中来
    // 1、创建文件字符输入流管道与源文件接通
    try (
            Reader fr = new FileReader("F:/Users/Typora/input.txt");
    ) {
        // 2、定义一个字符数组,用于装读取到的字符内容
        char[] buffer = new char[3];
        int len;    // 记录每次读取到的字符数组长度
        while ((len = fr.read(buffer)) != -1) {
            // 3、把字符数组中的内容按照一定的编码格式,按照一定的格式,输出到控制台
            String str = new String(buffer, 0, len);
            System.out.print(str);
        }
        // 扩展:文件字符输入流每次读取多个字符,减少系统调用,性能较好,而且读取中文是按照字符读取,不会出现乱码! ---- 一种读取中文很好的方案
    } catch (Exception e) {
        e.printStackTrace();
    }

6.2 字符输出流FileWriter
1)认识
  • 以内存为基准,把内存中的数据以字符的形式写出到文件中去

2)write()方法写数据
public static void main(String[] args) {
        // 目标:搞清楚文件字符输出流的使用
        try(
                // 1、创建FileWriter对象,指定写入的目的地
                FileWriter fw = new FileWriter("F:/Users/Typora/output.txt");
                ){
            // 2、写一个字符出去
            fw.write(65);   // 65是ASCII码,A
            fw.write("\r\n");

            // 3、写一个字符串出去
            fw.write("java");
            fw.write("\r\n");
            // 写字符串的一部分
            fw.write("Hello", 1, 2);
            fw.write("\r\n");

            // 4、写一个字符数组出去
            char[] chars = {'a', 'b', 'c'};
            fw.write(chars);
            fw.write("\r\n");

            // 5、写一个字符数组的一部分出去
            fw.write(chars, 1, 2);
            fw.write("\r\n");

            // fw.flush(); // 刷新缓冲区,将数据写入到目的地中
            // 刷新后,流可以继续使用
            fw.close(); // 关闭流,关闭包含了刷新!关闭后流不再可用!

        }catch (Exception e){
            e.printStackTrace();
        }
    }

⚠️ 刷新数据:fw.flush()

7. 缓冲流

7.1 缓冲字节流

💡提高字节输入流读取数据的性能

  • 文件复制
public static void main(String[] args) {
        // 目标:了解缓冲字节流的使用
    String srcPath = "F:/Users/Typora/input.txt";
    String destPath = "F:/Users/Typora/output.txt";

    copyFile(srcPath, destPath);

    }

public static void copyFile(String srcPath, String destPath) {
    //1、创建一个文件字节输入流管道与源文件接通,一个文件字节输出流管道与目标文件接通
    try (
            // 这里只能放置资源对象,用完后,最终会自动调用close()方法关闭资源
            InputStream fis = new FileInputStream(srcPath);
            // 把低级的字节输入流转换成高级的缓冲字节输入流
            InputStream bis = new BufferedInputStream(fis); // 多态
            FileOutputStream fos = new FileOutputStream(destPath);
            // 把低级的字节输出流转换成高级的缓冲字节输出流
            OutputStream bos = new BufferedOutputStream(fos);
    ) {
        // 2、读取一个字节数组,写入一个字节数组,循环读取,循环写入
        byte[] buffer = new byte[1024];
        int len;
        while ((len = bis.read(buffer)) != -1) {
            bos.write(buffer, 0, len);  // 写入一个字节数组,从数组的哪个索引开始读,读几个字节
        }
        System.out.println("复制完成!");
    }catch(Exception e){
        e.printStackTrace();
    }
}
7.2 缓冲字符流

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

public static void main(String[] args) {
        // 目标:缓冲字符输入流/缓冲字符输出流
        try(
                Reader fr = new FileReader("F:/Users/Typora/input.txt");
                Writer fw = new FileWriter("F:/Users/Typora/output.txt");
                // readLine是BufferedReader新增的,不用Reader多态创建
                BufferedReader br = new BufferedReader(fr);
                BufferedWriter bw = new BufferedWriter(fw);
                ){
            String line;
            while ((line = br.readLine()) != null){
                System.out.println(line);
                bw.write(line); // 写入
                bw.newLine();   // 换行
            }

        }catch (Exception e){
            e.printStackTrace();
        }
}
7.3 缓冲区vs不使用缓冲区

缓冲区的 read() 方法:

  • 先获取一整块数据到缓冲池,然后在从缓冲池里一个一个字节获取,或者一个一个字节数组获取

不使用缓冲区:

  • 每次都是从磁盘中获取

8. 其他流

8.1 字符输入转换流InputStreamReader:字节流->字符流
  • 解决不同编码时,字符流读取文本内容乱码的问题

解决思路:

① 获取文件的原始字节流

② 再将其按真实的字符集编码转成字符输入流

③ 这样字符输入流中的字符就不乱码了

在这里插入图片描述

public static void main(String[] args) {
    // 目标:认识字符输入转换流InputStreamReader的用法
    try(
            // 先提取文件的原始字节流
            InputStream is = new FileInputStream("F:\\Study\\Java\\javaseprojectmax\\day03-file-io\\src\\com\\study\\intput");
            // 再把字节输入流转换为字符输入流
            Reader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
            // 再把字符输入流转换为字符缓冲输入流
            BufferedReader br = new BufferedReader(isr);
            ){

        String line;
        while((line = br.readLine())!= null){
            System.out.println(line);
        }

    }catch(Exception e){

    }
}
8.2 打印流:PrintStream 、PrintWriter
  • 可以实现更方便、更高效的打印数据出去 >>> 写数据

使用字节输出流/字符输出流时,会将数字字符转成对应ASCII码的英文字符

8.3 特殊数据流:DataInputStream/DataOutputStream -> 网络通信收发数据

DataOutputStream:

  • 允许把数据和其类型一并写出去

public static void main(String[] args) {
    try(
            DataOutputStream dos = new DataOutputStream(new FileOutputStream("f:/Users/Typora/output.txt"));
            ){
        dos.writeBoolean(true);
        dos.writeByte(127);
        dos.writeChar('a');
        dos.writeShort(32767);
        dos.writeInt(2147483647);
        dos.writeDouble(3.1415926);
    }catch(Exception e){
        e.printStackTrace();
    }
}
public static void main(String[] args) {
    try(
            DataInputStream dis = new DataInputStream(new FileInputStream("f:/Users/Typora/output.txt"));
            ){
        System.out.println(dis.readBoolean());
        System.out.println(dis.readByte());
        System.out.println(dis.readChar());
        System.out.println(dis.readShort());
        System.out.println(dis.readInt());
        System.out.println(dis.readDouble());
    }catch(Exception e){
        e.printStackTrace();
    }
}

💡DataOutputStream对象使用write方法写数据时,也包含其类型,在文本上是乱码,在读取时通过DataInputStream读取数据即可以还原数据

9. IO框架

9.1 框架:
  • 一个预先写好的代码库或一组工具,旨在简化和加速开发过程
  • 形式:
    • 一般是把类、接口等编译成class形式,再压缩成一个.jar结尾的文件发行出去

IO框架: 下载链接

  • 封装了Java提供的对文件、数据进行操作的代码,对外提供了更简单的方式来对文件进行操作,对数据进行读写等

9.2 基本使用

File srcFile = new File("F:/Users/Typora/input.txt");
File destFile = new File("F:/Users/Typora/copy.txt");
FileUtils.copyFile(srcFile, destFile);  // 复制文件,如果没有会新建文件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值