JAVA基础加强篇09——IO流

IO流概述

IO流也称为输入、输出流,就是用来读写数据的。

在这里插入图片描述

IO 流概述

  • I 表示 input,是数据从硬盘文件读入到内存的过程,称之输入,负责读。

  • O 表示 output,是内存程序的数据从内存写出到硬盘文件的过程,称之输出,负责写。

    在这里插入图片描述

IO 流的分类

  • 按流的方向分

    在这里插入图片描述

  • 按流中的数据最小单位分为

    在这里插入图片描述

总结流的四大类:

  • 字节输入流:以内存为基准,来自磁盘文件/网络中的数据以字节的形式读入到内存中去的流称为字节输入流。
  • 字节输出流:以内存为基准,把内存中的数据以字节写出到磁盘文件或者网络中去的流称为字节输出流。
  • 字符输入流:以内存为基准,来自磁盘文件/网络中的数据以字符的形式读入到内存中去的流称为字符输入流。
  • 字符输出流:以内存为基准,把内存中的数据以字符写出到磁盘文件或者网络介质中去的流称为字符输出流。

在这里插入图片描述

在这里插入图片描述

总结

  1. IO 流的作用?
    • 读写文件数据的
  2. IO 流是怎么划分的,大体分为几类,各自的作用?
    • 字节流:字节输入流,字节输出流(读写字节数数据的)
    • 字符流:字符输入流,字符输出流(读写字符数据的)

字节流的使用

文件字节输入流:每次读取一个字节

在这里插入图片描述

文件字节输入流:FileInputStream
  • 作用:以内存为基准,把磁盘文件中的数据以字节的形式读取到内存中去。

    在这里插入图片描述

/**
 * @author : gxd
 * @date : 2022/7/7 9:20
 * 文件字节输入流:FileInputStream
 * - 作用:以内存为基准,把磁盘文件中的数据以字节的形式读取到内存中去。
 * 构造器:
 * - public FileInputStream(File file):创建字节输入流管道与源文件对象接通
 * - public FileInputStream(String name):创建字节输入流管道与源文件路径接通
 * 方法:
 * - public abstract int read():每次读取一个字节返回,如果字节已经没有可读的返回 -1
 * 小结:
 *    一个一个字节读取中文数据输出其实是被淘汰的,性能极差!
 *    一个一个字节读取中文数据输出,会主席安阶段中文字节的情况,无法避免读取中文输出乱码的问题。
 */
public class FileInputStreamTest1 {
    public static void main(String[] args) throws Exception {
        //1、创建一个文件字节输入流管道与源文件接通
        //InputStream is = new FileInputStream(new File("file-io-app/src/data.txt"));
        //简化写法
        InputStream is = new FileInputStream("file-io-app/src/data.txt");

        //2、读取一个字节返回(每次读取一滴水)
        //int b1 = is.read();
        //System.out.println((char) b1);
        //
        //int b2 = is.read();
        //System.out.println((char) b2);
        //
        //int b3 = is.read();
        //System.out.println((char) b3);
        //
        //int b4 = is.read();//读取完毕返回-1
        //System.out.println(b4);

        //3、使用循环改进
        //定义一个变量记录每次读取的字节   a  b  3  爱
        //                            o  o  o  [ooo]
        int b;
        while ((b = is.read()) != -1){
            System.out.print((char) b);
        }
    }
}
总结
  1. 文件字节输入流,每次读取一个字节的 api 是哪个?

    在这里插入图片描述

  2. 每次读取一个字节存在什么问题?

    • 性能较慢
    • 读取中文字符输出无法编码乱码问题。

文件字节输入流:每次读取一个字节数组

文件字节输入流: FileInputStream
  • 作用:以内存为基准,把磁盘文件中的数据以字节的形式读取到内存中。

    在这里插入图片描述
    g)]

/**
 * @author : gxd
 * @date : 2022/7/7 9:44
 * 目标:使用文件字节输入流每次读取一个字节数组的数据。
 */
public class FileInputStreamTest2 {
    public static void main(String[] args) throws Exception {
        //1、创建一个文件字节输入流管道与源文件接通
        InputStream is = new FileInputStream("file-io-app/src/data02.txt");

        //2、定义一个字节数组,用于读取字节数组
        //byte[] buffer = new byte[3];//3B
        //int len = is.read(buffer);
        //System.out.println("读取了几个字节:" + len);
        //String rs = new String(buffer);
        //System.out.println(rs);
        //
        //int len1 = is.read(buffer);
        //System.out.println("读取了几个字节:" + len1);
        //String rs1 = new String(buffer);
        //System.out.println(rs1);
         buffer = [a b c]
        //
         buffer = [a b c] ==> [c d c]
        //int len2 = is.read(buffer);
        //System.out.println("读取了几个字节:" + len2);
        读取多少倒出多少
        //String rs2 = new String(buffer,0,len2);
        //System.out.println(rs2);
        //
        //int len3 = is.read(buffer);
        //System.out.println(len3);//读取完毕返回 -1

        //3、改进使用循环,内次读取一个字节数组
        byte[] buffer = new byte[3];
        int len;//记录内次读取的字节数。
        while ((len = is.read(buffer)) != -1){
            //读取多少倒出多少
            System.out.print(new String(buffer,0,len));
        }
    }
}
总结
  1. 文件字节输入流,每次读取一个字节数组的 api 是哪个?

    在这里插入图片描述
    blog.csdnimg.cn/d344ede93492438190e9e4edb700be6d.png#pic_center)

  2. 每次读取一个字节数组存在什么问题?

    • 读取的性能得到了提示
    • 读取中文字符输出无法避免乱码问题。

文件字节输入流:一次读完全部字节

  1. 如何使用字节输入流读取中文内容输出不乱码呢?
    • 定义一个与文件一样大的字节数组,一次性读取完文件的全部字节。
  2. 直接把文件数据全部读取到一个字节数组可以避免乱码,是否存在问题?
    • 如果文件过大,字节数组可能引起内存溢出。
方式一
  • 自己定义一个字节数组与文件的大小一样大,然后使用读取字节数组的方法,一次性读取完毕。

    在这里插入图片描述

方式二
  • 官方为字节输入流 InputStream 提供了如下 API 可以直接把文件的全部数据读取到一个字节数组中

    在这里插入图片描述

总结
  1. 如何使用字节输入流读取中文内容输出不乱码呢?
    • 一次性读取完全部字节。
    • 可以定义与文件一样大的字节数组读取,也可以使用官方 API。
  2. 直接把文件数据全部读取到一个字节数组可以避免乱码,是否存在问题?
    • 如果文件过大,定义的字节数组可能引起内存溢出。

文件字节输出流:写字节数据到文件

在这里插入图片描述

文件字节输出流:FileOutputStream
  • 作用:以内存为基准,把内存中的数据以字节的形式写出到磁盘文件中去的流。

    在这里插入图片描述

文件字节输出流(FileOutputStream)写数据出去的 API

在这里插入图片描述

流的关闭与刷新

在这里插入图片描述

/**
 * @author : gxd
 * @date : 2022/7/7 11:00
 * 文件字节输出流:FileOutputStream
 * - 作用:以内存为基准,把内存中的数据以字节的形式写出到磁盘文件中去的流。
 * 构造器:
 * - public FileOutputStream(File file):创建字节输出流管道与源文件对象接通
 * - public FileOutputStream(File file, boolean append):创建字节输出流管道与源文件对象接通,可追加数据
 * - public FileOutputStream(String name):创建字节输出流管道与源文件路径接通
 * - public FileOutputStream(String name, boolean append):创建字节输出流管道与源文件路径接通,可追加数据
 * 方法:
 * - public abstract void write(int b):写一个字节出去
 * - public void write(byte b[]):写一个字节数组出去
 * - public void write(byte b[], int off, int len):写一个字节数组的一部分出去。
 *
 */
public class FileOutputStreamTest4 {
    public static void main(String[] args) throws Exception {
        //1、创建一个文件字节输出流管道与目标文件接通
        OutputStream os = new FileOutputStream("file-io-app/src/out04.txt",true);//追加数据管道
        //OutputStream os = new FileOutputStream("file-io-app/src/out04.txt");//先清空之前的数据,写新数据进入
        //2、写数据出去
        //a、public abstract void write(int b):写一个字节出去
        os.write('a');
        os.write(98);
        os.write("\r\n".getBytes());//换行
        //os.write('徐');// [ooo]

        //b、public void write(byte b[]):写一个字节数组出去。
        byte[] buffer = {'a',97,98,99};
        os.write(buffer);
        os.write("\r\n".getBytes());//换行

        byte[] buffer2 = "我是中国人".getBytes();
        //byte[] buffer2 = "我是中国人".getBytes("GBK");
        os.write(buffer2);
        os.write("\r\n".getBytes());//换行

        //c、public void write(byte b[], int off, int len):写一个字节数组的一部分出去。
        byte[] buffer3 = {'a',97,98,99};
        os.write(buffer3,0,3);
        os.write("\r\n".getBytes());//换行

        //os.flush();//写数据必须,刷新数据,可以继续使用流
        os.close();//释放资源,包含了刷新的!关闭后流不可以使用了
    }
}
总结
  1. 字节输出流写数据的方法有哪些

    在这里插入图片描述

  2. 字节输出流如何实现数据追加

    在这里插入图片描述

  3. 字节输出流如何实现写出去额的数据能换行

    • os.write(“\r\n”.getBytes())
  4. 如何让写出去的数据能成功生效?

    • flush()刷新数据
    • close()方法是关闭流,关闭包含刷新,关闭后流不可以继续使用了。

文件拷贝

在这里插入图片描述

案例 文件拷贝

需求:

  • 把某个视频复制到其他目录下的“b.avi”

思路:

  1. 根据数据源创建字节输入流对象
  2. 根据目的地创建字节输出流对象
  3. 读取数据,复制视频
  4. 释放资源
/**
 * @author : gxd
 * @date : 2022/7/7 14:12
 * 目标:学会使用字节流完成文件的复制(支持一切文件类型的复制)
 * 案例 文件拷贝
 * 需求:
 * - 把某个视频复制到其他目录下的“b.avi”
 * 思路:
 * 1. 根据数据源创建字节输入流对象
 * 2. 根据目的地创建字节输出流对象
 * 3. 读取数据,复制视频
 * 4. 释放资源
 */
public class CopyTest5 {
    public static void main(String[] args) {
        try {
            //1、创建一个字节输入流管道与原视频接通
            InputStream is = new FileInputStream("C:/Users/admin/Pictures/Camera Roll/王者视频.mp4");

            //2、创建一个字节输出流管道与目标文件接通
            OutputStream os = new FileOutputStream("C:/Users/admin/Desktop/new.mp4");

            //3、定义一个字节数组转移数据
            byte[] buffer = new byte[1024];
            int len;//记录每次读取的字节数
            while ((len = is.read(buffer)) != -1){
                os.write(buffer,0,len);
            }
            System.out.println("复制成功了!");

            //4、关闭流。
            os.close();
            is.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qgM46g2a-在这里插入图片描述

总结
  1. 字节流适合做一切文件数据的拷贝吗?
    • 任何文件的底层都是字节,拷贝是一字不漏的转移字节,只要前后文件格式、编码一致没有任何问题。

资源释放的方式

try-catch-finally

try-catch-finally
  • finally:在异常处理时提供 finally 块来执行所有清除操作,比如说 IO 流中的释放资源
  • 特点:被 finally 控制的语句最终一定会执行,除非 JVM 退出
  • 异常处理标准格式:try…catch…finally
try-catch-finally格式

在这里插入图片描述

/**
 * @author : gxd
 * @date : 2022/7/7 15:04
 * 目标:学会使用 finally 释放资源。
 *
 * try-catch-finally
 * - finally:在异常处理时提供 finally 块来执行所有清除操作,比如说 IO 流中的释放资源
 * - 特点:被 finally 控制的语句最终一定会执行,除非 JVM 退出
 * - 异常处理标准格式:try…catch…finally
 */
public class TryCatchFinallyTest1 {
    public static void main(String[] args) {
        InputStream is = null;
        OutputStream os = null;
        try {
            //1、创建一个字节输入流管道与原视频接通
            is = new FileInputStream("C:/Users/admin/Pictures/Camera Roll/王者视频.mp4");

            //2、创建一个字节输出流管道与目标文件接通
            os = new FileOutputStream("C:/Users/admin/Desktop/new.mp4");

            //3、定义一个字节数组转移数据
            byte[] buffer = new byte[1024];
            int len;//记录每次读取的字节数
            while ((len = is.read(buffer)) != -1){
                os.write(buffer,0,len);
            }
            System.out.println("复制成功了!");
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //无论代码是正常结束,还是出现异常都要最后执行这里
            System.out.println("===============finally=============");
            //4、关闭流。
            try {
                if (os != null){
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (is != null){
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println(test(10,0));
    }

    private static int test(int a, int b) {
        try {
            int c = a / b;
            return c;
        } catch (Exception e) {
            e.printStackTrace();
            return -1111;//计算出现bug。
        } finally {
            //哪怕上面有 return 语句执行,也必须先执行完这里才可以!
            //开发中不建议在这里加 return,如果加了,返回的永远是这里的数据了,这样会出问题!
            //return 100;
        }
    }
}
总结
  1. try-catch-finally的作用
    • finally 代码块是最终一定要执行的,可以在代码执行完毕的最后用于释放资源。

try-with-resource

  1. finally 虽然可以用于释放资源,但是释放资源的代码过于繁琐?
  2. 有什么方法可以简化?

在这里插入图片描述

JDK7 和 JDK9 中都简化了资源释放操作
  • 基本做法:

    在这里插入图片描述

  • JDK7 改进方案:

    在这里插入图片描述

/**
 * @author : gxd
 * @date : 2022/7/7 15:04
 * 目标:学会 JDK7 简化了资源释放操作。
 *
 * try-with-resource
 * 1. finally 虽然可以用于释放资源,但是释放资源的代码过于繁琐?
 * 2. 有什么方法可以简化?
 */
public class TryCatchFinallyTest2 {
    public static void main(String[] args) {
        try(
                //这里面只能放置资源对象,用完会自动关闭:自动调用资源对象的close
                //1、创建一个字节输入流管道与原视频接通
                InputStream is = new FileInputStream("C:/Users/admin/Pictures/Camera Roll/王者视频.mp4");
                //2、创建一个字节输出流管道与目标文件接通
                OutputStream os = new FileOutputStream("C:/Users/admin/Desktop/new.mp4");

                //int age = 23;//这里只能放资源
                MyConnection connection = new MyConnection();//最终会自动调用资源的 close 方法
                ) {

            //3、定义一个字节数组转移数据
            byte[] buffer = new byte[1024];
            int len;//记录每次读取的字节数
            while ((len = is.read(buffer)) != -1){
                os.write(buffer,0,len);
            }
            System.out.println("复制成功了!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class MyConnection implements AutoCloseable{
    @Override
    public void close() throws Exception {
        System.out.println("连接资源被成功释放了!");
    }
}
  • JDK9改进方案

    在这里插入图片描述

/**
 * @author : gxd
 * @date : 2022/7/7 15:04
 * 目标:学会 JDK9 简化了资源释放操作。
 *
 * try-with-resource
 * 1. finally 虽然可以用于释放资源,但是释放资源的代码过于繁琐?
 * 2. 有什么方法可以简化?
 */
public class TryCatchFinallyTest3 {
    public static void main(String[] args) throws Exception {
        //1、创建一个字节输入流管道与原视频接通
        InputStream is = new FileInputStream("C:/Users/admin/Pictures/Camera Roll/王者视频.mp4");
        //2、创建一个字节输出流管道与目标文件接通
        OutputStream os = new FileOutputStream("C:/Users/admin/Desktop/new.mp4");
        try(is;os) {
            //3、定义一个字节数组转移数据
            byte[] buffer = new byte[1024];
            int len;//记录每次读取的字节数
            while ((len = is.read(buffer)) != -1){
                os.write(buffer,0,len);
            }
            System.out.println("复制成功了!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
注意
  • JDK7 以及 JDK9 的()中只能放置资源对象,否则报错

  • 什么是资源呢?

  • 资源都是实现了 Closeable/AutoCloseable 接口的类对象

    在这里插入图片描述

总结
  1. try-catch-resource 的作用
    • 自动释放资源、代码简洁

字符流的使用

  1. 字节流读取中文输出可能会存在什么问题?
    • 会乱码。或者内存溢出。
  2. 读取中文输出,哪个流更合适,为什么?
    • 字符流更合适,最小单位是按照单个字符读取的。

在这里插入图片描述

文件字符输入流-一次读取一个字符

在这里插入图片描述

文件字符输入流:Reader
  • 作用:以内存为基准,把磁盘文件中的数据以字符的形式读取到内存中去。

    在这里插入图片描述

/**
 * @author : gxd
 * @date : 2022/7/7 17:10
 * 文件字符输入流:Reader
 * - 作用:以内存为基准,把磁盘文件中的数据以字符的形式读取到内存中去。
 *
 * 构造器:
 * - public FileReader(File file):创建字符输入流管道与源文件对象接通
 * - public FileReader(String fileName):创建字符输入流管道与源文件路径接通
 * 方法:
 * - public int read():每次读取一个字符返回,如果字符已经没有可读的返回 -1
 * - public int read(char cbuf[]):每次读取一个字符数组,返回读取的字符个数,如果字符已经没有可读的返回 -1
 * 小结:
 *   字符流一个一个字符的读取文本内容输出,可以解决中文读取乱码的问题。
 *   字符流很适合操作文本文件内容。
 *   但是:一个一个字符的读取文本内容性能较差!
 */
public class FileReaderTest1 {
    public static void main(String[] args) throws Exception {
        //目标:每次读取一个字符
        //1、创建一个字符输入流管道与源文件接通
        FileReader fr = new FileReader("file-io-app/src/data03.txt");

        //2、读取一个字符返回,没有可读的字符返回 -1
        //int code = fr.read();
        //System.out.print((char) code);
        //
        //int code1 = fr.read();
        //System.out.print((char) code1);

        //3、使用循环读取字符
        int code;
        while ((code = fr.read()) != -1){
            System.out.print((char) code);
        }
    }
}
总结
  1. 文件字符输入流,每次读取一个字符的 api 是哪个?

    在这里插入图片描述

  2. 字符流的好处,每次读取一个字符存在什么问题?

    • 读取中文字符不会出现乱码(如果代码和文件编码一致)
    • 性能较慢

文件字符输入流-一次读取一个字符数组

在这里插入图片描述

文件字符输入流:FileReader
  • 作用:以内存为基准,把磁盘文件中的数据以字符的形式读取到内存中去。

    在这里插入图片描述

/**
 * @author : gxd
 * @date : 2022/7/7 17:10
 * 文件字符输入流:Reader
 * - 作用:以内存为基准,把磁盘文件中的数据以字符的形式读取到内存中去。
 *
 * 构造器:
 * - public FileReader(File file):创建字符输入流管道与源文件对象接通
 * - public FileReader(String fileName):创建字符输入流管道与源文件路径接通
 * 方法:
 * - public int read():每次读取一个字符返回,如果字符已经没有可读的返回 -1
 * - public int read(char cbuf[]):每次读取一个字符数组,返回读取的字符个数,如果字符已经没有可读的返回 -1
 * 小结:
 *   字符流按照字符数组循环读取数据,可以解决中文读取输出乱码的问题,而且性能也较好!!
 */
public class FileReaderTest2 {
    public static void main(String[] args) throws Exception {
        //1、创建一个字符输入流管道与源文件接通
        FileReader fr = new FileReader("file-io-app/src/data03.txt");

        //2、用循环,每次读取一个字符数组的数据。 
        char[] buffer = new char[1024];
        int len;
        while ((len = fr.read(buffer)) != -1){
            String rs = new String(buffer, 0, len);
            System.out.print(rs);
        }
    }
}
总结
  1. 文件字符输入流,每次读取一个字符数组的 api 是哪个?

    在这里插入图片描述

  2. 每次读取一个字符数组的优势?

    • 读取的性能得到了提升

文件字符输出流

在这里插入图片描述

在这里插入图片描述

文件字符输出流:FileWriter
  • 作用:以内存为基准,把内存中的额数据以字符的形式写出到磁盘文件中去的流。

    在这里插入图片描述

文件字符输出流(FileWrite) 写出数据出去的 API

在这里插入图片描述
blog.csdnimg.cn/79a43904cd0e47b9b1d1330b5d063e6b.png#pic_center)

流的关闭与刷新

在这里插入图片描述

/**
 * @author : gxd
 * @date : 2022/7/8 9:47
 * 文件字符输出流:FileWriter
 * - 作用:以内存为基准,把内存中的额数据以字符的形式写出到磁盘文件中去的流。
 *
 * 构造器:
 * - public FileWriter(File file):创建字符输出流管道与源文件对象接通
 * - public FileWriter(File file, boolean append):创建字符输出流管道与源文件对象接通,可追加数据
 * - public FileWriter(String fileName):创建字符输出流管道与源文件路径接通
 * - public FileWriter(String fileName, boolean append):创建字符输出流管道与源文件路径接通,可追加数据
 * 方法:
 * - public void write(int c):写一个字符
 * - public void write(char cbuf[]):写入一个字符数组
 * - public void write(char cbuf[], int off, int len):写入字符数组的一部分
 * - public void write(String str):写一个字符串
 * - public void write(String str, int off, int len):写一个字符串的一部分
 *        fw.write("\r\n");//换行
 * 结论:读写字符文件数据建议使用字符流,复制文件建议使用字节流
 */
public class FileWriterTest3 {
    public static void main(String[] args) throws IOException {
        //1、创建一个字符输出流管道与目标文件接通
        //FileWriter fw = new FileWriter("file-io-app/src/out05.txt");//覆盖管道,每次启动都会清空文件之前的数据
        FileWriter fw = new FileWriter("file-io-app/src/out05.txt",true);//追加数据

        //a、public void write(int c):写一个字符
        fw.write(98);
        fw.write('a');
        fw.write("徐");//不会出问题了
        fw.write("\r\n");//换行

        //b、public void write(String str):写一个字符串
        fw.write("abc我是中国人");
        fw.write("\r\n");//换行

        //c、public void write(char cbuf[]):写入一个字符数组
        char[] chars = "abc我是中国人".toCharArray();
        fw.write(chars);
        fw.write("\r\n");//换行

        //d、public void write(String str, int off, int len):写一个字符串的一部分
        fw.write("abc我是中国人",0,5);
        fw.write("\r\n");//换行

        //e、public void write(char cbuf[], int off, int len)::写入字符数组的一部分
        fw.write(chars,3,5);
        fw.write("\r\n");//换行

        //fw.flush();//刷新后流可以继续使用
        fw.close();//关闭包含刷新,关闭后流不能使用
    }
}
总结
  1. 字符输出流写数据的方式有哪些?

    在这里插入图片描述

  2. 字符输出流如何实现数据追加

    在这里插入图片描述

  3. 字符输出流如何实现写出去的数据能换行

    • fw.write(“\r\n”)
  4. 字符输出流写完数据后必须做什么?

    • flush()刷新数据
    • close()方法是关闭流,关闭包含刷新,关闭后流不可以继续使用了。
  5. 字节流、字符流如何选择使用?

    • 字节流适合做一切文件数据的拷贝(音视频,文本)
    • 字节流不适合读取中文内容输出
    • 字符流适合做文本文件的操作(读,写)

IO流(二)课程安排

在这里插入图片描述

缓冲流

缓冲流概述

缓冲流概述
  • 缓冲流也称为高效流、或者高级流。之前学习的字节流可以成为原始流。

  • 作用:缓冲流自带缓冲区、可以提高原始字节流、字节流读写数据的性能。

    在这里插入图片描述

在这里插入图片描述

总结
  1. 缓冲流的作用?
    • 缓冲流自带缓冲区、可以提高原始字节流、字符流读写数据的性。
  2. 缓冲流有几种?
    • 字节缓冲流
      • 字节缓冲输入流:BufferedInputStream
      • 字节缓冲输出流:BufferedOutputStream
    • 字符缓冲流
      • 字符缓冲输入流:BufferedReader
      • 字符缓冲输出流:BufferedWriter

字节缓冲流

在这里插入图片描述

在这里插入图片描述

字节缓冲流性能优化原理:
  • 字节缓冲输入流自带了8KB缓冲池,以后我们直接从缓冲池读取数据,所以性能较好。
  • 字节缓冲输出流自带了8KB缓冲池,数据就直接写入到缓冲池中去,写数据性能级高了。
字节缓冲流
  • 字节缓冲输入流:BufferedInputStream,提高字节输入流读取数据的性能,读写功能上并无变化。

  • 字节缓冲输出流:BufferedOutputStream,提高字节输出流程读取数据的性能,读写功能上并无变化。

    在这里插入图片描述

/**
 * @author : gxd
 * @date : 2022/7/8 15:04
 * 目标:使用字节缓冲流完成数据的读写操作。
 *
 * 字节缓冲流
 * - 字节缓冲输入流:BufferedInputStream,提高字节输入流读取数据的性能,读写功能上并无变化。
 * - 字节缓冲输出流:BufferedOutputStream,提高字节输出流程读取数据的性能,读写功能上并无变化。
 */
public class ByteBufferTest {
    public static void main(String[] args) {
        try(
                //这里面只能放置资源对象,用完会自动关闭:自动调用资源对象的close
                //1、创建一个字节输入流管道与原视频接通
                InputStream is = new FileInputStream("C:/Users/admin/Pictures/Camera Roll/王者视频.mp4");
                //把原始的字节输入流包装成高级的缓存字节输入流
                InputStream bis = new BufferedInputStream(is);
                //2、创建一个字节输出流管道与目标文件接通
                OutputStream os = new FileOutputStream("C:/Users/admin/Desktop/new.mp4");
                //把字节输出流管道包装成高级的缓存字节输出流管道
                OutputStream bos = new BufferedOutputStream(os);
        ) {

            //3、定义一个字节数组转移数据
            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();
        }
    }
}
总结
  1. 字节缓冲流为什么提高了操作数据的性能?
    • 字节缓冲流自带8KB缓冲区
    • 可以提高原始字节流、字节流读写数据的性能
  2. 字节缓冲流的功能如何调用?
    • public BufferedInputStream(InputStream in)
    • public BufferedOutputStream(OutputStream out)

字节缓冲流的性能分析

步骤 分别使用不同的方式复制大视频观察性能情况

需求:

  • 分别使用低级字节流和高级字节缓冲流拷贝大视频,记录耗时。

分析:

  • 使用低级的字节流按照一个一个字节的形式复制文件。
  • 使用低级的字节流按照一个一个字节数组的形式复制文件。
  • 使用高级的缓冲字节流按照一个一个字节的形式复制文件。
  • 使用高级的缓冲字节流按照一个一个字节数组的形式复制文件。
/**
 * @author : gxd
 * @date : 2022/7/8 15:27
 * 目标:字节缓冲流的性能分析
 * 步骤 分别使用不同的方式复制大视频观察性能情况
 *
 * 需求:
 * - 分别使用低级字节流和高级字节缓冲流拷贝大视频,记录耗时。
 *
 * 分析:
 * - 使用低级的字节流按照一个一个字节的形式复制文件。
 * - 使用低级的字节流按照一个一个字节数组的形式复制文件。
 * - 使用高级的缓冲字节流按照一个一个字节的形式复制文件。
 * - 使用高级的缓冲字节流按照一个一个字节数组的形式复制文件。
 */
public class ByteBufferTimeTest {
    private static final String SRC_FILE = "C:/Users/admin/Pictures/Camera Roll/王者视频.mp4";
    private static final String DEST_FILE = "C:/Users/admin/Desktop/";

    public static void main(String[] args) {
        copy1();//使用低级的字节流按照一个一个字节的形式复制文件:慢的让人简直无法忍受,直接被淘汰、
        copy2();//使用低级的字节流按照一个一个字节数组的形式复制文件:比较慢,但是还是可以忍受的!
        copy3();//缓冲流一个一个字节复制:很慢,不建议使用
        copy4();//缓冲流一个一个字节数组赋值:飞快,直接太完美了(推荐使用)
    }

    /**
     * 缓冲流一个一个字节数组赋值
     */
    private static void copy4() {
        long startTime = System.currentTimeMillis();
        try (
                //1、创建低级的字节输入流与源文件接通
                InputStream is = new FileInputStream(SRC_FILE);
                //把原始的字节输入流包装成高级的缓存字节输入流
                InputStream bis =  new BufferedInputStream(is);
                //2、创建低级的字节输出流与目标文件接通
                OutputStream os = new FileOutputStream(DEST_FILE + "new4.mp4");
                //把字节输出流管道包装成高级的缓存字节输出流管道
                OutputStream bos = new BufferedOutputStream(os);
        ){
            byte[] buffer = new byte[1024];
            int len;
            while ((len = bis.read(buffer)) != -1){
                bos.write(buffer,0,len);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("缓冲流一个一个字节数组赋值耗时:" + (endTime - startTime)/1000.0 + "s");
    }

    /**
     * 缓冲流一个一个字节复制
     */
    private static void copy3() {
        long startTime = System.currentTimeMillis();
        try (
                //1、创建低级的字节输入流与源文件接通
                InputStream is = new FileInputStream(SRC_FILE);
                //把原始的字节输入流包装成高级的缓存字节输入流
                InputStream bis =  new BufferedInputStream(is);
                //2、创建低级的字节输出流与目标文件接通
                OutputStream os = new FileOutputStream(DEST_FILE + "new3.mp4");
                //把字节输出流管道包装成高级的缓存字节输出流管道
                OutputStream bos = new BufferedOutputStream(os);
                ){
            int len;
            while ((len = bis.read()) != -1){
                bos.write(len);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("缓冲流一个一个字节复制耗时:" + (endTime - startTime)/1000.0 + "s");
    }

    /**
     * 使用低级的字节流按照一个一个字节数组的形式复制文件
     */
    private static void copy2() {
        long startTime = System.currentTimeMillis();
        try (
                //1、创建低级的字节输入流与源文件接通
                InputStream is = new FileInputStream(SRC_FILE);
                //2、创建低级的字节输出流与目标文件接通
                OutputStream os = new FileOutputStream(DEST_FILE + "new2.mp4")
        ){
            byte[] buffer = new byte[1024];
            int len;
            while ((len = is.read(buffer)) != -1){
                os.write(buffer,0,len);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("使用低级的字节流按照一个一个字节数组的形式复制文件耗时:" + (endTime - startTime)/1000.0 + "s");
    }

    /**
     * 使用低级的字节流按照一个一个字节的形式复制文件
     */
    private static void copy1() {
        long startTime = System.currentTimeMillis();
        try (
                //1、创建低级的字节输入流与源文件接通
                InputStream is = new FileInputStream(SRC_FILE);
                //2、创建低级的字节输出流与目标文件接通
                OutputStream os = new FileOutputStream(DEST_FILE + "new1.mp4")
        ){
            //3、定义一个变量记录每次读取的字节(一个一个字节的赋值)
            int len;
            while ((len = is.read()) != -1){
                os.write(len);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("使用低级的字节流按照一个一个字节的形式复制文件耗时:" + (endTime - startTime)/1000.0 + "s");
    }
}
总结
  1. 推荐使用哪种方式提高字节流读写数据的性能?
    • 建议使用字节缓冲输入流,字节缓冲输出流,结合字节数组的方式,目前来看是性能最优的组合。

字符缓冲流

在这里插入图片描述

字符缓冲输入流
  • 字符缓冲输入流:BufferedReader。

  • 作用:提高字符输入流读取数据的性能,除此之外多了按照行读取数据的功能。

    在这里插入图片描述

字符缓冲输入流新增功能

在这里插入图片描述

/**
 * @author : gxd
 * @date : 2022/7/8 17:17
 * 字符缓冲输入流
 * - 字符缓冲输入流:BufferedReader。
 * - 作用:提高字符输入流读取数据的性能,除此之外多了按照行读取数据的功能。
 *
 * 构造器:
 * - public BufferedReader(Reader in):可以把低级的字符输入流包装成一个高级的缓冲字符输入流管道,从而提高字符输入流的性能
 *
 * 新增方法:(经典代码)
 * - public String readLine():读取一行数据返回,如果读取完毕,无行可读返回 null
 */
public class BufferedReaderTest1 {
    public static void main(String[] args) {
        try (
                //1、创建一个文件字符流与源文件接通
                Reader fr = new FileReader("io-app2/src/data1.txt");
                BufferedReader br = new BufferedReader(fr);
                ){
            //2、用循环,每次读取一个字符数组的数据
            //char[] buffer = new char[1024];//1K字符
            //int len;
            //while ((len = br.read(buffer)) != -1){
            //    String rs = new String(buffer, 0, len);
            //    System.out.println(rs);
            //}

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

        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
字符缓冲输出流
  • 字符缓冲输出流:BufferedWriter。

  • 作用:提高字符输出流写数据的性能,除此之外多了换行功能。

    在这里插入图片描述

/**
 * @author : gxd
 * @date : 2022/7/8 17:31
 * 目标:字符缓冲输出流的使用,学会它多出来的一个功能:newLine();
 * - 字符缓冲输出流:BufferedWriter。
 * - 作用:提高字符输出流写数据的性能,除此之外多了换行功能
 *
 * 构造器:
 * - public BufferedWriter(Writer out):可以把低级的字符输出流包装成一个高级的缓冲字符输出流管道,从而提高字符输出流写数据的性能
 * 方法:
 * - public void newLine():换行
 */
public class BufferedWriterTest2 {
    public static void main(String[] args) {
        try (
                //1、创建一个字符输出流管道与目标文件接通
                //FileWriter fw = new FileWriter("io-app2/src/out2.txt");//覆盖管道,每次启动都会清空文件之前的数据
                FileWriter fw = new FileWriter("io-app2/src/out2.txt",true);//追加数据
                BufferedWriter bw = new BufferedWriter(fw);
                ){
            
            //a、public void write(int c):写一个字符
            bw.write(98);
            bw.write('a');
            bw.write("徐");//不会出问题了
            bw.newLine();//换行

            //b、public void write(String str):写一个字符串
            bw.write("abc我是中国人");
            bw.newLine();//换行

            //c、public void write(char cbuf[]):写入一个字符数组
            char[] chars = "abc我是中国人".toCharArray();
            bw.write(chars);
            bw.newLine();//换行

            //d、public void write(String str, int off, int len):写一个字符串的一部分
            bw.write("abc我是中国人",0,5);
            bw.newLine();//换行

            //e、public void write(char cbuf[], int off, int len)::写入字符数组的一部分
            bw.write(chars,3,5);
            bw.newLine();//换行
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
总结
  1. 字符缓冲流为什么提高了操作数据的性能?
    • 字符缓冲流自带 8K 缓冲区
    • 可以提高原始字符流读写数据的性能
  2. 字符缓冲流的功能如何使用?
    • public BufferedReader(Reader r)
    • 性能提升了,多了 readLine() 按照行读取的功能
    • public BufferedWriter(Writer w)
    • 性能提升了,多了 newLine() 换行的功能
案例 拷贝出师表到另一个文件,恢复顺序

需求:

  • 把《出师表》的文章顺序进行恢复到一个新文件中。

分析:

  1. 定义一个缓冲字符输入流管道与源文件接通。
  2. 定义一个 List 集合存储读取的每行数据。
  3. 定义一个循环按照行读取数据,存入到 List 集合中去。
  4. 对 List 集合中的每行数据按照首字符编号升序排序。
  5. 定义一个缓存字符输出管道与目标文件接通。
  6. 遍历 List 集合中的每个元素,用缓冲输出管道写出并换行。

出师表:

十一.出师未捷身先死,长使英雄泪满襟。
四.侍中、侍郎郭攸之、费祎、董允等,此皆良实,志虑忠纯,是以先帝简拔以遗陛下。愚以为宫中之事,事无大小,悉以咨之,然后施行,必能裨补阙漏,有所广益。
玖.愿陛下托臣以讨贼兴复之效,不效,则治臣之罪,以告先帝之灵。若无兴德之言,则责攸之、祎、允等之慢,以彰其咎;陛下亦宜自谋,以咨诹善道,察纳雅言,深追先帝遗诏,臣不胜受恩感激。
五.将军向宠,性行淑均,晓畅军事,试用于昔日,先帝称之曰能,是以众议举宠为督。愚以为营中之事,悉以咨之,必能使行阵和睦,优劣得所。
三.宫中府中,俱为一体,陟罚臧否,不宜异同。若有作奸犯科及为忠善者,宜付有司论其刑赏,以昭陛下平明之理,不宜偏私,使内外异法也。
二.先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠谏之路也。
十.今当远离,临表涕零,不知所言。
柒.臣本布衣,躬耕于南阳,苟全性命于乱世,不求闻达于诸侯。先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,咨臣以当世之事,由是感激,遂许先帝以驱驰。后值倾覆,受任于败军之际,奉命于危难之间,尔来二十有一年矣。
八.先帝知臣谨慎,故临崩寄臣以大事也。受命以来,夙夜忧叹,恐托付不效,以伤先帝之明,故五月渡泸,深入不毛。今南方已定,兵甲已足,当奖率三军,北定中原,庶竭驽钝,攘除奸凶,兴复汉室,还于旧都。此臣所以报先帝而忠陛下之职分也。至于斟酌损益,进尽忠言,则攸之、祎、允之任也。
陆.亲贤臣,远小人,此先汉所以兴隆也;亲小人,远贤臣,此后汉所以倾颓也。先帝在时,每与臣论此事,未尝不叹息痛恨于桓、灵也。侍中、尚书、长史、参军,此悉贞良死节之臣,愿陛下亲之信之,则汉室之隆,可计日而待也。
一.出师表

程序

/**
 * @author : gxd
 * @date : 2022/7/9 23:37
 * 案例 拷贝出师表到另一个文件,恢复顺序
 *
 * 需求:
 * - 把《出师表》的文章顺序进行恢复到一个新文件中。
 *
 * 分析:
 * 1. 定义一个缓冲字符输入流管道与源文件接通。
 * 2. 定义一个 List 集合存储读取的每行数据。
 * 3. 定义一个循环按照行读取数据,存入到 List 集合中去。
 * 4. 对 List 集合中的每行数据按照首字符编号升序排序。
 * 5. 定义一个缓存字符输出管道与目标文件接通。
 * 6. 遍历 List 集合中的每个元素,用缓冲输出管道写出并换行。
 */
public class BufferedCharTest3 {
    public static void main(String[] args) {
        try (
                //1、创建缓冲字符输入流管道与源文件接通
                BufferedReader br = new BufferedReader(new FileReader("io-app2/src/csb.txt"));
                //5、定义缓冲字符输出管道与目标文件接通
                BufferedWriter bw = new BufferedWriter(new FileWriter("io-app2/src/newcsb.txt"));
                ){
            //2、定义一个 List 集合存储每行内容
            List<String> data = new ArrayList<>();
            //3、定义循环,按照行读取文章
            String line;
            while ((line = br.readLine()) != null){
                data.add(line);
            }
            //4、排序
            //Collections.sort(list);//1. - 9.这样的排序直接排序就行
            //自定义排序规则
            List<String> sizes = new ArrayList<>();
            Collections.addAll(sizes,"一","二","三","四","五","陆","柒","八","玖","十","十一");
            Collections.sort(data,(o1,o2) -> sizes.indexOf(o1.substring(0,o1.indexOf("."))) - sizes.indexOf(o2.substring(0,o2.indexOf("."))));

            //6、遍历集合汇总的每行文章写出去,且要换行
            for (String d : data) {
                bw.write(d);
                bw.newLine();//换行
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

转换流

  1. 之前我们使用字符流读取中文是否有乱码?
    • 没有的,因为代码编码和文件编码都是 UTF-8。
  2. 如果代码编码和文件编码不一致,使用字符流直接读取还能不乱码吗?
    • 会乱码
    • 文件编码和读取的编码必须一致才不会乱码。
  3. 如何解决呢?
    • 使用字符输入转换流
    • 可以提取文件(GBK)的原始字节流,原始字节不会存在问题。
    • 然后把字节流以指定编码转换成字符输入流,这样字符输入流中的字符就不乱码了
  4. 如果需要控制写出去的字符使用的编码,怎么办?
    • 可以把字符以指定编码获取字节后再使用字节输出流写出去:
    • 也可以使用字符输出转换流实现。

问题引出:不同编码读取乱码问题

步骤 使用相同编码读取不同编码的文件内容

需求:分别使用如下两种方式读取文件内容

  1. 代码编码是 UTF-8,文件编码也是 UTF-8,使用字符流读取观察输出的中文字符结果。
  2. 代码编码是 UTF-8,文件编码使用 GBK,使用字符流读取观察输出的中文字符结果。
/**
 * @author : gxd
 * @date : 2022/7/11 9:16
 * 步骤 使用相同编码读取不同编码的文件内容
 *
 * 需求:分别使用如下两种方式读取文件内容
 * 1. 代码编码是 UTF-8,文件编码也是 UTF-8,使用字符流读取观察输出的中文字符结果。
 * 2. 代码编码是 UTF-8,文件编码使用 GBK,使用字符流读取观察输出的中文字符结果。
 */
public class CharSetTest {
    public static void main(String[] args) {
        try (
                //代码:UTF-8  文件:UTF-8 不会乱码
                //1、创建一个文件字符流与源文件接通
                //Reader fr = new FileReader("io-app2/src/csb.txt");

                //代码:UTF-8  文件:GBK  乱码
                Reader fr = new FileReader("C:/Users/admin/Pictures/文件/data.txt");
                //a、把低级的字符输入流包装成高级的缓冲字符输入流。
                BufferedReader br = new BufferedReader(fr);
        ){

            String line;
            while ((line = br.readLine()) != null){
                System.out.println(line);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
总结
  1. 字符流直接读取文本内容。
    • 必须文件和代码编码一致才不会乱码
    • 如果文件和代码编码不一致,读取将出现乱码。

字符输入转换流

在这里插入图片描述

字符输入转换流
  • 字符输入转换流:InputStreamReader,可以把原始的字节流按照指定编码转换成字符输入流。

    在这里插入图片描述

/**
 * @author : gxd
 * @date : 2022/7/11 9:37
 * 目标:字符输入转换流
 * 字符输入转换流:InputStreamReader,可以把原始的字节流按照指定编码转换成字符输入流。
 *
 * 构造器
 * - public InputStreamReader(InputStream in): 可以把原始的字节流按照代码默认编码转成字符输入流。几乎不用,与默认的 FileReader 一样。
 * - public InputStreamReader(InputStream in, String charsetName):介意把原始的字节流按照指定编码转换成字符输入流,这样字符流中的字符就不乱码了(核心)
 * 小结:
 *    字符输入转换流 InputStreamReader:作用:可以解决字符流读取不同编码乱码的问题。
 *    public InputStreamReader(InputStream in, String charsetName):介意把原始的字节流按照指定编码转换成字符输入流,这样字符流中的字符就不乱码了(核心)
 */
public class InputStreamReaderTest1 {
    public static void main(String[] args) {
        try (
                //代码:UTF-8  文件:GBK  乱码
                //1、提取GBK文件的原始字节流。
                InputStream is  = new FileInputStream("C:/Users/admin/Pictures/文件/data.txt");
                //2、把原始字节流转成字符输入流
                //Reader isr = new InputStreamReader(is);//默认以UTF-8的方式转换成字符流。还是会乱码的 跟FileReader一样
                Reader isr = new InputStreamReader(is,"GBK");//以指定的GBK编码转换成字符输入流 完美的解决了乱码问题

                BufferedReader br = new BufferedReader(isr);
        ){

            String line;
            while ((line = br.readLine()) != null){
                System.out.println(line);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
总结
  1. 字符输入转换流 InputStreamReader 作用:
    • 可以解决字符流读取不同编码乱码的问题
    • public InputStreamReader(InputStream in, String charsetName):可以指定编码把原始字节流转换成字符流,如此字符流中的字符不乱码。

字符输出转换流

在这里插入图片描述

字符输出转换流
  • 字符输出转换流:OutputStreamWriter,可以把字节输出流按照指定编码转换成字符输出流。

    在这里插入图片描述

/**
 * @author : gxd
 * @date : 2022/7/11 10:01
 * 目标: 字符输出转换流
 * - 字符输出转换流:OutputStreamWriter,可以把字节输出流按照指定编码转换成字符输出流。
 *
 * 构造器
 * - public OutputStreamWriter(OutputStream out):可以把原始的字节输出流按照代码默认编码转换成字符输出流。几乎不用,
 * - public OutputStreamWriter(OutputStream out, String charsetName):可以把原始的字节输出流按照指定编码转换成字符输出流。(重点)
 */
public class OutputStreamWriterTest2 {
    public static void main(String[] args) {
        try (
             OutputStream os = new FileOutputStream("io-app2/src/data2.txt");
             //Writer osw = new OutputStreamWriter(os);
             Writer osw = new OutputStreamWriter(os,"GBK");
             BufferedWriter bw = new BufferedWriter(osw);
             ){

            bw.write("aasdasfs阿首都废水大富科技撒旦教开发说");
            bw.write("aasdasfs阿首都废水大富科技撒旦教开发说");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
总结
  1. 字符输出转换流 OutputStreamWriter 的作用?
    • public OutputStreamWriter(OutputStream out, String charsetName)
    • 可以指定编码把字节输出流转换成字符输出流,从而可以指定写出去的字符编码!

序列化对象

对象序列化

在这里插入图片描述

在这里插入图片描述

对象序列化:
  • 作用:以内存为基准,把内存中的对象存储到磁盘文件中去,称为对象序列化。

  • 使用到的流式对象字节输出流:ObjectOutputStream

    在这里插入图片描述

ObjectOutputStream 序列化方法

在这里插入图片描述

注意
  • transient 修饰的成员变量不参与序列化了。

  • //申明序列化的版本号码
    //序列化的版本号与反序列化的版本号必须一致才不会出错!
    private static final long serialVersionUID = 1;
    

实体类:

 /**
 * @author : gxd
 * @date : 2022/7/11 10:33
 * 对象如果要序列化,必须实现Serializable序列化接口。
 */
public class Student implements Serializable {
    //申明序列化的版本号码
    //序列化的版本号与反序列化的版本号必须一致才不会出错!
    private static final long serialVersionUID = 1;
    private String name;
    private String loginName;
    // transient 修饰的成员变量不参与序列化了
    private transient String passWord;
    private int age;

    public Student() {
    }

    public Student(String name, String loginName, String passWord, int age) {
        this.name = name;
        this.loginName = loginName;
        this.passWord = passWord;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLoginName() {
        return loginName;
    }

    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", loginName='" + loginName + '\'' +
                ", passWord='" + passWord + '\'' +
                ", age=" + age +
                '}';
    }
}

程序:

/**
 * @author : gxd
 * @date : 2022/7/11 10:35
 * 目标:学会对象序列化,使用 ObjectOutputStream 把内存中的对象存入到磁盘文件中。
 * transient 修饰的成员变量不参与序列化了
 * - 作用:以内存为基准,把内存中的对象存储到磁盘文件中去,称为对象序列化。
 * - 使用到的流式对象字节输出流:ObjectOutputStream
 *
 * 构造器
 * - public ObjectOutputStream(OutputStream out):把低级字节输出流包装成高级的对象字节输出流。
 * 方法
 * - public final void writeObject(Object obj):把对象写出去到对象序列化流的文件中去
 */
public class ObjectOutputStreamTest1 {
    public static void main(String[] args) throws Exception {
        //1、创建学生对象
        Student student = new Student("张三","zhangsan","1314",21);

        //2、对象序列化:使用对象字节输出流包装字节输出流管道
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("io-app2/src/obj.txt"));

        //3、直接调用序列化方法
        oos.writeObject(student);

        //4、释放资源
        oos.close();

        System.out.println("序列化完成了~~~");
    }
}
总结
  1. 对象序列化的含义是什么?

    • 把对象数据存入到文件中去。
  2. 对象序列化用到了哪个流?

    • 对象字节输出流 ObjectOutputStream
    • public void writeObject(Object obj)
  3. 序列化对象的要求是怎么样的?

    • 对象必须实现序列化接口

对象反序列化

在这里插入图片描述

在这里插入图片描述

对象反序列化:
  • 使用到的流式对象字节输入流:ObjectInputStream

  • 作用:以内存为基准,把存储到磁盘文件中去的对象数据恢复成内存中的对象,称为对象反序列化。

    在这里插入图片描述

ObjectInputStream 序列化方法

在这里插入图片描述

/**
 * @author : gxd
 * @date : 2022/7/11 11:00
 * 目标:学会进行对象反序列化:使用对象字节输入流把文件中的对象恢复成内存中的 Java 对象。
 * - 使用到的流式对象字节输入流:ObjectInputStream
 * - 作用:以内存为基准,把存储到磁盘文件中去的对象数据恢复成内存中的对象,称为对象反序列化。
 *
 * 构造器
 * - public ObjectInputStream(InputStream in):把低级字节输入流包装成高级的对象字节输入流
 * 方法
 * - public final Object readObject():把存储到磁盘文件中去的对象数据恢复成内存中的对象返回
 */
public class ObjectInputStreamTest2 {
    public static void main(String[] args) throws Exception {
        //1、创建对象字节输入流管道包装低级的字节输入流管道
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("io-app2/src/obj.txt"));

        //2、调用对象字节输入流的反序列化方法
        Student student = (Student) ois.readObject();
        System.out.println(student);

        //3、释放资源
        ois.close();
    }
}
总结
  1. 对象反序列化的含义是什么?
    • 把磁盘中的对象数据恢复到内存的 Java 对象中。
  2. 对象反序列化用到了哪个流?
    • 对象字节输入流 ObjectInputStream
    • public Object readObject()

打印流

在这里插入图片描述

printStream、PrintWriter

打印流
  • 作用:打印流可以实现方便、高效的打印数据到文件中去。打印流一般是指:PrintStream,PrintWriter两个类。
  • 可以实现打印什么数据就是什么数据,例如打印整数97写出去就是97,打印 boolean 的 true,写出去就是 true。
PrintStream

在这里插入图片描述

在这里插入图片描述

/**
 * @author : gxd
 * @date : 2022/7/11 11:40
 * 目标: 学会使用打印流 高效 方便写数据到文件
 * - 作用:打印流可以实现方便、高效的打印数据到文件中去。打印流一般是指:PrintStream,PrintWriter两个类。
 * - 可以实现打印什么数据就是什么数据,例如打印整数97写出去就是97,打印 boolean 的 true,写出去就是 true。
 *
 * 构造器
 * - public PrintStream(OutputStream out):打印流直接通向字节输出流管道
 * - public PrintStream(File file):打印流直接通向文件对象
 * - public PrintStream(String fileName):打印流直接通向文件路径
 * 方法
 * -  public void print(Xxx xxx):打印任意类型的数据出去
 */
public class PrintTest {
    public static void main(String[] args) throws Exception {
        //1、创建一个打印流对象
        //PrintStream ps = new PrintStream(new FileOutputStream("io-app2/src/ps.txt"));
        PrintStream ps = new PrintStream("io-app2/src/ps.txt");

        ps.println(97);
        ps.println('a');
        ps.println(89.6);
        ps.println(true);
        ps.println("我是打印流输出的,我是什么就打印什么!");

        ps.close();
    }
}
PrintWriter

在这里插入图片描述

/**
 * @author : gxd
 * @date : 2022/7/11 11:40
 * 目标: 学会使用打印流 高效 方便写数据到文件
 * - 作用:打印流可以实现方便、高效的打印数据到文件中去。打印流一般是指:PrintStream,PrintWriter两个类。
 * - 可以实现打印什么数据就是什么数据,例如打印整数97写出去就是97,打印 boolean 的 true,写出去就是 true。
 *
 * 构造器
 * - public PrintStream(OutputStream out):打印流直接通向字节输出流管道
 * - public PrintStream(File file):打印流直接通向文件对象
 * - public PrintStream(String fileName):打印流直接通向文件路径
 * 方法
 * -  public void print(Xxx xxx):打印任意类型的数据出去
 */
public class PrintTest {
    public static void main(String[] args) throws Exception {
        //1、创建一个打印流对象
        //PrintStream ps = new PrintStream(new FileOutputStream("io-app2/src/ps.txt",true));//追加数据,在低级管道后面加 true
        //PrintWriter ps = new PrintWriter(new FileOutputStream("io-app2/src/ps.txt",true));
        //PrintStream ps = new PrintStream("io-app2/src/ps.txt");
        PrintWriter ps = new PrintWriter("io-app2/src/ps.txt");//打印功能上与 PrintStream 的使用没有区别

        ps.println(97);
        ps.println('a');
        ps.println(89.6);
        ps.println(true);
        ps.println("我是打印流输出的,我是什么就打印什么!");

        ps.close();
    }
}
PrintStream 和 PrintWriter 的区别
  • 打印数据功能上是一模一样的,都是使用方便,性能高效(核心优势)。
  • PrintStream 继承自字节输出流 OutputStream,支持写字节数据的方法。
  • PrintWriter 继承自字符输出流 Writer,支持写字符数据出去。
总结
  1. 打印流有几种?各有什么特点?
    • 打印流一般是指:PrintStream,PrintWriter两个类。
    • 打印功能2者是一样的使用方式
    • PrintStream 继承自字节输出流 OutputStream,支持写字节
    • PrintWriter 继承自字符输出流 Writer,支持写字符
  2. 打印流的优势是什么?
    • 两者在打印功能上都是使用方便,性能高效(核心优势)

输出语句的重定向

输出语句重定向
  • 属于打印流的一种应用,可以把输出语句的打印位置放到文件。

    在这里插入图片描述

/**
 * @author : gxd
 * @date : 2022/7/11 14:29
 * 目标: 了解输出语句重定向
 * - 属于打印流的一种应用,可以把输出语句的打印位置放到文件。
 *   PrintStream ps = new PrintStream("文件地址");
 *   System.setOut(ps);
 */
public class PrintTest2 {
    public static void main(String[] args) throws Exception {
        System.out.println("锦瑟无端五十弦,一弦一柱思华年。");
        System.out.println("庄生晓梦迷蝴蝶,望帝春心托杜鹃。");

        //改变输出语句的位置(重定向)
        PrintStream ps = new PrintStream("io-app2/src/log.txt");
        System.setOut(ps);//把系统打印流改成我们自己的打印流

        System.out.println("沧海月明珠有泪,蓝田日暖玉生烟。");
        System.out.println("此情可待成追忆?只是当时已惘然。");
    }
}

补充知识:Properties

在这里插入图片描述

Properties 属性集对象

  • 其实就是一个 Map 集合,但是我们一般不会当集合使用,因为 HashMap更好用。

Properties 核心作用

  • Properties 代表的是一个属性文件,可以把自己对象中的键值对信息存入到一个属性文件中去。
  • 属性文件:后缀是 .properties 结尾的文件,里面的内容都是 key=value,后续做系统配置信息系的。
Properties 的 API:
  • Properties 和 IO流结合的方法:

    在这里插入图片描述

写入:

/**
 * @author : gxd
 * @date : 2022/7/11 14:48
 * 目标:学习使用 Properties (写入)
 * Properties 属性集对象:
 * - 其实就是一个 Map 集合,但是我们一般不会当集合使用,因为 HashMap更好用。
 *
 * Properties 核心作用:
 * - Properties 代表的是一个属性文件,可以把自己对象中的键值对信息存入到一个属性文件中去。
 * - 属性文件:后缀是 .properties 结尾的文件,里面的内容都是 key=value,后续做系统配置信息系的。
 *
 * Properties 的 API:
 * - Properties 和 IO流结合的方法:
 * - public synchronized void load(InputStream inStream):从输入字节流读取属性列表(键和元素对)
 * - public synchronized void load(Reader reader):从输入字符流读取属性列表(键和元素对)
 * - public void store(OutputStream out, String comments):将此属性列表(键和元素对)写入此 Properties 表中,以适合使用 load(InputStream) 方法的格式写入输出字节流
 * - public void store(Writer writer, String comments):将此属性列表(键和元素对)写入此 Properties 表中,以适合使用 load(Reader) 方法的格式写入输出字符流
 * - public synchronized Object setProperty(String key, String value) :保存键值对(put)
 * - public String getProperty(String key):使用此属性列表中指定的键搜索属性值(get)
 * - public Set<String> stringPropertyNames():所有键的名称的集合(keySet())
 * 
 * 小结:
 *    Properties 可以保存键值对数据到属性文件
 */
public class PropertiesTest1 {
    public static void main(String[] args) throws Exception {
        //需求:使用Properties把键值对信息存入到属性文件中去。
        Properties properties = new Properties();
        properties.setProperty("admin","123456");
        properties.setProperty("root","000000");
        properties.setProperty("zwzl","888888");

        /**
         * 参数一:保存管道 字符输出流管道
         * 参数二:保存心得
         */
        properties.store(new FileWriter("io-app2/src/users.properties"),
                "This is users!!");
    }
}

读取:

/**
 * @author : gxd
 * @date : 2022/7/11 14:48
 * 目标:学习使用 Properties (读取)
 * Properties 属性集对象:
 * - 其实就是一个 Map 集合,但是我们一般不会当集合使用,因为 HashMap更好用。
 *
 * Properties 核心作用:
 * - Properties 代表的是一个属性文件,可以把自己对象中的键值对信息存入到一个属性文件中去。
 * - 属性文件:后缀是 .properties 结尾的文件,里面的内容都是 key=value,后续做系统配置信息系的。
 *
 * Properties 的 API:
 * - Properties 和 IO流结合的方法:
 * - public synchronized void load(InputStream inStream):从输入字节流读取属性列表(键和元素对)
 * - public synchronized void load(Reader reader):从输入字符流读取属性列表(键和元素对)
 * - public void store(OutputStream out, String comments):将此属性列表(键和元素对)写入此 Properties 表中,以适合使用 load(InputStream) 方法的格式写入输出字节流
 * - public void store(Writer writer, String comments):将此属性列表(键和元素对)写入此 Properties 表中,以适合使用 load(Reader) 方法的格式写入输出字符流
 * - public synchronized Object setProperty(String key, String value) :保存键值对(put)
 * - public String getProperty(String key):使用此属性列表中指定的键搜索属性值(get)
 * - public Set<String> stringPropertyNames():所有键的名称的集合(keySet())
 *
 * 小结:
 *    属性集对象可以加载读取属性文件中的数据!
 */
public class PropertiesTest2 {
    public static void main(String[] args) throws Exception {
        //需求:使用Properties读取属性文件中的键值对信息。
        Properties properties = new Properties();
        System.out.println(properties);

        //加载属性文件中的键值对数据到属性对象 Properties 中去。
        properties.load(new FileReader("io-app2/src/users.properties"));
        System.out.println(properties);

        String rs = properties.getProperty("admin");
        System.out.println(rs);

        Set<String> results = properties.stringPropertyNames();//所有键的名称的集合(keySet())
        results.forEach(System.out::println);
    }
}
总结
  1. Properties 的作用?
    • 可以存储 Properties 属性集的键值对数据到属性文件中去:
      • void store(Writer writer,String comments)
    • 可以加载属性文件中的数据到 Properties 对象中来:
      • void load(Reader reader)

补充知识:IO 框架

commons-io 概述

  • commons-io 是 apache 开源基金组织提供的一组有关 IO 操作的类库,可以提高 IO 功能开发的效率。
  • commons-io 工具包提供了很多有关 io 操作的类。有两个主要的类 FileUtils,IOUtils。

安装

  • 下载网址:https://commons.apache.org/proper/commons-io/

  • 选择版本,找到.zip结尾的下载。

  • 解压后其中,commons-io-2.11.0.jar为核心包,commons-io-2.11.0-javadoc.jar解压后是使用文档,commons-io-2.11.0-sources.jar源码包,commons-io-2.11.0-tests.jar测试包,commons-io-2.11.0-test-sources.jar源码测试包

    在这里插入图片描述

FileUtils 主要有如下方法:

在这里插入图片描述

步骤 导入 commons-io-2.11.jar 做开发

需求:

  • 使用 commons-io 简化 io流读写

分析:

  1. 在项目中创建一个文件夹:lib
  2. 将 commons-io-2.11.jar 文件复制到 lib 文件夹
  3. 在 jar 文件上点右键,选择 Add as Library -> 点击OK
  4. 在类中导包使用
/**
 * @author : gxd
 * @date : 2022/7/11 15:54
 * 目标:学会使用IO框架
 *
 * commons-io 概述
 * - commons-io 是 apache 开源基金组织提供的一组有关 IO 操作的类库,可以提高 IO 功能开发的效率。
 * - commons-io 工具包提供了很多有关 io 操作的类。有两个主要的类 FileUtils,IOUtils。
 *
 * 安装
 * - 下载网址:https://commons.apache.org/proper/commons-io/
 * - 选择版本,找到.zip结尾的下载。
 * - 解压后其中,commons-io-2.11.0.jar为核心包,commons-io-2.11.0-javadoc.jar解压后是使用文档,commons-io-2.11.0-sources.jar源码包,commons-io-2.11.0-tests.jar测试包,commons-io-2.11.0-test-sources.jar源码测试包
 *
 * 导入 commons-io-2.11.jar 做开发
 * 需求:
 * - 使用 commons-io 简化 io流读写
 *
 * 分析:
 * 1. 在项目中创建一个文件夹:lib
 * 2. 将 commons-io-2.11.jar 文件复制到 lib 文件夹
 * 3. 在 jar 文件上点右键,选择 Add as Library -> 点击OK
 * 4. 在类中导包使用
 *
 * 小结:
 *    IOUtils 和 FileUtils 可以方柏霓的赋值文件和文件夹!!
 */
public class CommonsIOTest1 {
    public static void main(String[] args) throws Exception {
        //1、完成文件复制!
        IOUtils.copy(new FileInputStream("C:/Users/admin/Pictures/Camera Roll/aa.jpg"),
                new FileOutputStream("io-app2/src/xin.jpg"));

        //2、完成文件复制到耨个文件夹下!
        FileUtils.copyFileToDirectory(new File("C:/Users/admin/Pictures/Camera Roll/aa.jpg"),new File("D:/"));

        //3、完成文件夹复制到某个文件夹下!
        FileUtils.copyDirectoryToDirectory(new File("C:/Users/admin/Pictures/Camera Roll"),new File("D:/new"));

        //4、删除指定文件夹
        FileUtils.deleteDirectory(new File("D:/new"));

        //JDK1.7 字节也做了一些一行代码完成复制的操作:New IO的技术
        Files.copy(Path.of("C:/Users/admin/Pictures/Camera Roll/aa.jpg"),Path.of("io-app2/src/xin2.jpg"));

        Files.deleteIfExists(Path.of("D:/new"));//只能删除空文件目录
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值