缓冲流、转换流、序列化流、装饰设计模式、comms-io工具包

缓冲流

概述

在这里插入图片描述

BufferedInputStream:字节缓冲输入流

/*
    java.io.BufferedInputStream:字节缓冲输入流 extends InputStream
    继承自父类共性的成员方法:
        - public void close() :关闭此输入流并释放与此流相关联的任何系统资源。
        - public abstract int read(): 从输入流读取数据的下一个字节。
        - public int read(byte[] b): 从输入流中读取一些字节数,并将它们存储到字节数组 b中 。
    构造方法:
        BufferedInputStream(InputStream in) 创建一个默认缓冲区大小的BufferedInputStream对象
        BufferedInputStream(InputStream in, int size) 创建一个指定缓冲区大小的BufferedInputStream对象
        参数:
            InputStream in:传递字节输入流,可以传递InputStream的任意子类对象
                我们可以传递FileInputStream对象,缓冲流就会给FileInputStream对象增加一个缓冲区(数组),
                提高FileInputStream对象读取文件的效率
            int size:指定缓冲区的大小(数组的大小),不指定使用默认
                 private static int DEFAULT_BUFFER_SIZE = 8192; 默认缓冲区的大小
    -----------------------------------------
    使用步骤(重点):
        1.创建BufferedInputStream对象,构造方法中传递FileInputStream对象
        2.使用BufferedInputStream对象中的方法read,以字节的方式读取文件
        3.释放资源
 */
public class Demo01BufferedInputStream {
    public static void main(String[] args) throws IOException {
        //1.创建BufferedInputStream对象,构造方法中传递FileInputStream对象
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("day16\\1.txt"));
        //2.使用BufferedInputStream对象中的方法read,以字节的方式读取文件
        //- public abstract int read(): 从输入流读取数据的下一个字节。
        /*int len = 0;
        while ((len = bis.read())!=-1){
            System.out.println((char)len);
        }*/

        //- public int read(byte[] b): 从输入流中读取一些字节数,并将它们存储到字节数组 b中 。
        int len= 0;
        byte[] bytes = new byte[1024];
        while ((len = bis.read(bytes))!=-1){
            System.out.println(new String(bytes,0,len));
        }

        //3.释放资源
        bis.close();
    }
}

BufferedOutputStream:字节缓冲输出流

/*
    java.io.BufferedOutputStream:字节缓冲输出流 extends OutputStream
    继承自父类的共性成员方法:
        - public void close() :关闭此输出流并释放与此流相关联的任何系统资源。
        - public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出。
        - public void write(byte[] b):将 b.length字节从指定的字节数组写入此输出流。
        - public void write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。
        - public abstract void write(int b) :将指定的字节输出流。
    构造方法:
        BufferedOutputStream(OutputStream out)创建一个默认缓冲区大小的BufferedOutputStream对象
        BufferedOutputStream(OutputStream out, int size) 创建一个指定缓冲区大小的BufferedOutputStream对象
        参数:
            OutputStream out:字节输出流,可以传递OutputStream的任意子类对象
                我们可以传递FileOutputStream对象,缓冲流就会给FileOutputStream对象增加一个缓冲区
                提供FileOutputStream对象写入数据的效率
            int size:指定缓冲区的大小(数组的大小),不指定使用默认
    使用步骤:
       1.创建BufferedOutputStream对象,构造方法中传递FileOutputStream对象
       2.使用BufferedOutputStream对象中的方法write,把数据写入到内部缓冲区中
       3.使用BufferedOutputStream对象中的方法flush,把内部缓冲区中的数据刷新到文件中
       4.释放资源(会先调用flush方法刷新数据)
 */
public class Demo02BufferedOutputStream {
    public static void main(String[] args) throws IOException {
        //1.创建BufferedOutputStream对象,构造方法中传递FileInputStream对象
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("day16\\2.txt"));
        //2.使用BufferedOutputStream对象中的方法write,把数据写入到内部缓冲区中
        bos.write("你好".getBytes());
        //3.使用BufferedOutputStream对象中的方法flush,把内部缓冲区中的数据刷新到文件中
        //bos.flush();
        //4.释放资源(会先调用flush方法刷新数据)
        bos.close();
    }
}

使用缓冲流读写效率高于字节/字符流

BufferedReader:字符缓冲输入流

特有方法: String readLine() 读取一个文本行。一次读取一行的数据

/*
    java.io.BufferedReader:字符缓冲输入流 extends Reader
    继承自父类共性的成员方法:
        - public void close() :关闭此流并释放与此流相关联的任何系统资源。
        - public int read(): 从输入流读取一个字符。
        - public int read(char[] cbuf): 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中 。
    构造方法:
        BufferedReader(Reader in) 创建一个使用默认大小输入缓冲区的缓冲字符输入流。
        BufferedReader(Reader in, int sz) 创建一个使用指定大小输入缓冲区的缓冲字符输入流。
        参数:
            Reader in:字符输入流,可以传递Reader的任意子类对象
                我们可以传递FileReader对象,缓冲流就会给FileReader对象增加一个缓冲区,提高FileReader对象读取文件的效率
           int sz:指定缓冲区的大小(数组的大小),不指定使用默认
    特有的成语方法:(重点)
        String readLine() 读取一个文本行。一次读取一行的数据
            通过下列字符之一即可认为某行已终止:换行 ('\n')、回车 ('\r') 或回车后直接跟着换行("\r\n")。
        返回值:
            包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null
    -----------------------------------
    使用步骤(重点):
        1.创建BufferedReader对象,构造方法中传递FileReader对象
        2.使用BufferedReader对象中的方法read|readLine,读取文件
        3.释放资源
 */
public class Demo04BufferedReader {
    public static void main(String[] args) throws IOException {
        //1.创建BufferedReader对象,构造方法中传递FileReader对象
        BufferedReader br = new BufferedReader(new FileReader("day16\\3.txt"));
        //2.使用BufferedReader对象中的方法read|readLine,读取文件
        //- public int read(): 从输入流读取一个字符。
        /*int len = 0;
        while ((len = br.read())!=-1){
            System.out.print((char)len);
        }*/

        //String readLine() 读取一个文本行。一次读取一行的数据
        /*
            我们发现使用readLine方法读取文件,也是一个重复的过程,所以可以使用循环 优化
            不知道文件中有多少行数据,使用while循环
            while循环结束的条件,readLine方法返回null
            文件中有"null"仅仅是一个字符串,字符串的内容是null,不是默认值null,可以被读取到
         */
        String line;
        while ((line = br.readLine())!=null){
            System.out.print(line);//abc1abc2abc3 不会读取换行符号
        }


        /*String line = br.readLine();
        System.out.println(line);//abc1

        line = br.readLine();
        System.out.println(line);//abc2

        line = br.readLine();
        System.out.println(line);//abc3

        line = br.readLine();
        System.out.println(line);//null没有数据返回null*/

        //3.释放资源
        br.close();
    }
}

BufferedWriter:字符缓冲输出流

特有方法: void newLine() 写入一个行分隔符

/*
    java.io.BufferedWriter:字符缓冲输出流 extends Writer
    继承自父类共性的成员方法:
        - public abstract void close() :关闭此输出流并释放与此流相关联的任何系统资源。
        - public abstract void flush() :刷新此输出流并强制任何缓冲的输出字符被写出。
        - public void write(int c) :写出一个字符。
        - public void write(char[] cbuf):将 b.length字符从指定的字符数组写出此输出流。
        - public abstract void write(char[] b, int off, int len) :从指定的字符数组写出 len字符,从偏移量 off开始输出到此输出流。
        - public void write(String str) :写出一个字符串。
        - void write(String str, int off, int len) 写入字符串的某一部分。
    构造方法:
        BufferedWriter(Writer out) 创建一个使用默认大小输出缓冲区的缓冲字符输出流。
        BufferedWriter(Writer out, int sz) 创建一个使用给定大小输出缓冲区的新缓冲字符输出流。
        参数:
          Writer out:传递字符输出流,可以传递Writer的任意子类对象
                我们可以传递FileWriter对象,缓冲流就会给FileWriter增加一个缓冲区,提高FileWriter写入数据的效率
          int sz:指定缓冲区的大小(数组的大小),不指定使用默认
    特有的成员方法(重点):
        void newLine() 写入一个行分隔符。写一个换行,根据系统不同,而写不同的换行符号
            windows:\r\n
            linux:/n
            mac:/r
    -------------------------------
    使用步骤(重点):
        1.创建BufferedWriter对象,构造方法传递FileWriter对象
        2.使用BufferedWriter对象中的方法write,把数据写入到内存缓冲区中
        3.使用BufferedWriter对象中的方法flush,把内存缓冲区中的数据刷新到文件中
        4.释放资源(会先调用flush方法刷新数据)
 */
public class Demo05BufferedWriter {
    public static void main(String[] args) throws IOException {
        //1.创建BufferedWriter对象,构造方法传递FileWriter对象
        BufferedWriter bw = new BufferedWriter(new FileWriter("day16\\4.txt",true));
        //2.使用BufferedWriter对象中的方法write,把数据写入到内存缓冲区中
        for (int i = 1; i <= 10; i++) {
            //bw.write("hello"+i+"\r\n");
            bw.write("hello"+i);
            bw.newLine();//写换行
        }
        //3.使用BufferedWriter对象中的方法flush,把内存缓冲区中的数据刷新到文件中
        bw.flush();
        //4.释放资源(会先调用flush方法刷新数据)
        bw.close();
    }
}

文本排序

/*
    练习:文本排序
    分析:
        1.创建ArrayList集合对象,泛型使用String
        2.创建BufferedReader对象,构造方法中传递FileReader对象
        3.创建BufferedWriter对象,构造方法中传递FileWriter对象
        4.使用BufferedReader对象中的方法readLine,以行的方式读取文件
        5.把读取到的每行数据,存储到Arraylist集合中
        6.使用Collections集合工具类中的方法sort,根据比较器写的规则进行排序
        7.遍历ArrayList集合,获取每一行数据
        8.使用BufferedWriter对象中的方法write,把每一行数据写入到内存缓冲区中
        9.使用BufferedWriter对象中的方法newLine每写完一行数据之后写一个换行
        10.释放资源(会先调用flush方法刷新数据)
 */
public class Demo06Test {
    public static void main(String[] args) throws IOException {
        //1.创建ArrayList集合对象,泛型使用String
        ArrayList<String> list = new ArrayList<>();
        //2.创建BufferedReader对象,构造方法中传递FileReader对象
        BufferedReader br = new BufferedReader(new FileReader("day16\\csb.txt"));
        //3.创建BufferedWriter对象,构造方法中传递FileWriter对象
        BufferedWriter bw = new BufferedWriter(new FileWriter("day16\\csbzx.txt"));
        //4.使用BufferedReader对象中的方法readLine,以行的方式读取文件
        String line;
        while ((line = br.readLine())!=null){
            //5.把读取到的每行数据,存储到Arraylist集合中
            list.add(line);
        }
        //6.使用Collections集合工具类中的方法sort,根据比较器写的规则进行排序
        Collections.sort(list, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                //元素的首字母升序排序
                return o1.charAt(0)-o2.charAt(0);
            }
        });
        //7.遍历ArrayList集合,获取每一行数据
        for (String s : list) {
            //8.使用BufferedWriter对象中的方法write,把每一行数据写入到内存缓冲区中
            bw.write(s);
            //9.使用BufferedWriter对象中的方法newLine每写完一行数据之后写一个换行
            bw.newLine();
        }
        //10.释放资源(会先调用flush方法刷新数据)
        bw.close();
        br.close();
    }
}

转换流

编码表

就是生活中的文字和计算机中文字的对应关系表

a–>97–>01100001==>存储到计算机中

中–>20013–>‭0010000000001011‬==>存储到计算机中

编码:把能看懂的文字,转换为看不懂的文字(字符==>字节)

解码:把看不懂的文字,转换为能看懂的文字(字节==>字符)

常用的编码表:

ASCII字符集 :英文,数字,标点符号和计算机中文字的对应关系

​ 0–>48 A–>65 a–>97

ISO-8859-1字符集:拉丁码表

  • 拉丁码表,别名Latin-1,用于显示欧洲使用的语言,包括荷兰、丹麦、德语、意大利语、西班牙语等。
  • ISO-5559-1使用单字节编码,兼容ASCII编码。不支持中文

GBxxx字符集:国标

  • GB就是国标的意思,是为了显示中文而设计的一套字符集。兼容ASCII表
  • GB2312:简体中文码表。
  • GBK:目前操作系统默认中文码表(简体,繁体),存储一个中文使用2个字节
  • GB18030:最新的中文码表。包含的文字最全(简体,繁体,少数民族,日韩文字)

Unicode字符集 :万国码

  • UTF-8:最常用的万国表,兼容所有国家的文字
  • 编码规则:
    • 128个US-ASCII字符,只需一个字节编码。
    • 拉丁文等字符,需要二个字节编码。
    • 大部分常用字(含中文),使用三个字节编码。
    • 其他极少使用的Unicode辅助字符,使用四字节编码。

编码会引出一个问题(重点)

即使用FileReader读取GBK编码的文件会出现乱码问题,导致编码和解码不一致

/*
    使用FileReader读取GBK编码的文件:会出现乱码
        GBK:一个中文占用2个字节
        UTF-8:一个中文占用3个字节
   FileReader只能读取IDEA默认编码的文件(utf-8)
 */
public class Demo01FileReader {
    public static void main(String[] args) throws IOException {
        //FileReader fr = new FileReader("day16\\我是UTF_8编码的文件.txt");//你好
        FileReader fr = new FileReader("day16\\我是GBK编码的文件.txt");//◧◧◧ 乱码
        int len = 0;
        while ((len = fr.read())!=-1){
            System.out.print((char)len);
        }
        fr.close();
    }
}

转换流的原理

在这里插入图片描述

InputStreamReader:字符转换输入流(重点)

注意:
InputStreamReader构造方法指定的编码表名称必须和文件的编码一致,否则会出现乱码

/*
    java.io.InputStreamReader:字符转换输入流 extends Reader
    作用:
        InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。
        解码:字节==>字符
     有继承自父类的共性成员方法:
        - public void close() :关闭此流并释放与此流相关联的任何系统资源。
        - public int read(): 从输入流读取一个字符。
        - public int read(char[] cbuf): 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中 。
     构造方法:
        InputStreamReader(InputStream in)创建一个使用默认字符集的 InputStreamReader。
        InputStreamReader(InputStream in, String charsetName) 创建使用指定字符集的 InputStreamReader。
        参数:
            InputStream in:传递字节输入流,可以传递InputStream的任意子类对象(读取文件中的字节)
            String charsetName:编码表名称,不区分大小写,可以传递GBK(gbk),UTF-8(utf-8),...;不写IDEA默认使用UTF-8
     ---------------------------
     使用步骤:
        1.创建InputStreamReader对象,构造方法中传递FileInputStream对象和编码表名称
        2.使用InputStreamReader对象中的方法read,读取文件
        3.释放资源
    注意:
        InputStreamReader构造方法指定的编码表名称必须和文件的编码一致,否则会出现乱码
 */
public class Demo02InputStreamReader {
    public static void main(String[] args) throws IOException {
        //read_UTF_8();
        read_GBK();
    }

    /*
        使用字符转换输入流读取GBK编码的文件
     */
    private static void read_GBK() throws IOException {
        //1.创建InputStreamReader对象,构造方法中传递FileInputStream对象和编码表名称
        //不传递编码表名称默认使用UTF-8编码
        //InputStreamReader isr = new InputStreamReader(new FileInputStream("day16\\我是GBK编码的文件.txt"));//◨◨◧ 乱码
        InputStreamReader isr = new InputStreamReader(new FileInputStream("day16\\我是GBK编码的文件.txt"),"GBK");
        //2.使用InputStreamReader对象中的方法read,读取文件
        int len = 0;
        while ((len = isr.read())!=-1){
            System.out.println((char)len);
        }
        //3.释放资源
        isr.close();
    }

    /*
        使用字符转换输入流读取UTF-8编码的文件
     */
    private static void read_UTF_8() throws IOException {
        //1.创建InputStreamReader对象,构造方法中传递FileInputStream对象和编码表名称
        //InputStreamReader isr = new InputStreamReader(new FileInputStream("day16\\我是UTF_8编码的文件.txt"),"UTF-8");
        //不传递编码表名称默认使用UTF-8编码
        InputStreamReader isr = new InputStreamReader(new FileInputStream("day16\\我是UTF_8编码的文件.txt"));
        //2.使用InputStreamReader对象中的方法read,读取文件
        int len = 0;
        while ((len = isr.read())!=-1){
            System.out.println((char)len);
        }
        //3.释放资源
        isr.close();
    }
}

OutputStreamWriter:字符转换输出流(重点)

/*
    java.io.OutputStreamWriter:字符转换输出流 extends Writer
    作用:
        OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。
        编码:字符==>字节
    继续自父类的共性成员方法:
        - public abstract void close() :关闭此输出流并释放与此流相关联的任何系统资源。
        - public abstract void flush() :刷新此输出流并强制任何缓冲的输出字符被写出。
        - public void write(int c) :写出一个字符。
        - public void write(char[] cbuf):将 b.length字符从指定的字符数组写出此输出流。
        - public abstract void write(char[] b, int off, int len) :从指定的字符数组写出 len字符,从偏移量 off开始输出到此输出流。
        - public void write(String str) :写出一个字符串。
        - void write(String str, int off, int len) 写入字符串的某一部分。
    构造方法:
        OutputStreamWriter(OutputStream out)创建使用默认字符编码的 OutputStreamWriter。
        OutputStreamWriter(OutputStream out, String charsetName) 创建使用指定字符集的 OutputStreamWriter。
        参数:
            OutputStream out:传递字节输出流,我们可以传递OutputStream的任意子类对象(把字符转换后的字节写入到文件中)
            tring charsetName:编码表名称,不区分大小写,可以传递GBK(gbk),UTF-8(utf-8),...;不写IDEA默认使用UTF-8
    -------------------------
    使用步骤(重点):
        1.创建OutputStreamWriter对象,构造方法中传递FileOutputStream对象和指定的编码表名称
        2.使用OutputStreamWriter对象中的方法write,把数据写入到内存缓冲区中(字符==>字节)
        3.使用OutputStreamWriter对象中的方法flush,把内存缓冲区中的数据刷新到文件中(使用字节输出流把字节写入到文件中)
        4.释放资源(会先调用flush方法刷新数据)
 */
public class Demo03OutputStreamWriter {
    public static void main(String[] args) throws IOException {
        //write_utf8();
        write_gbk();
    }

    /*
        使用字符转换输出流写gbk编码格式的文件
     */
    private static void write_gbk() throws IOException {
        //1.创建OutputStreamWriter对象,构造方法中传递FileOutputStream对象和指定的编码表名称
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day16\\gbk.txt"),"gbk");
        //2.使用OutputStreamWriter对象中的方法write,把数据写入到内存缓冲区中(字符==>字节)
        osw.write("你好");
        //3.使用OutputStreamWriter对象中的方法flush,把内存缓冲区中的数据刷新到文件中(使用字节输出流把字节写入到文件中)
        osw.flush();
        //4.释放资源(会先调用flush方法刷新数据)
        osw.close();
    }

    /*
        使用字符转换输出流写utf-8编码格式的文件
     */
    private static void write_utf8() throws IOException {
        //1.创建OutputStreamWriter对象,构造方法中传递FileOutputStream对象和指定的编码表名称
        //OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day16\\utf-8.txt"),"utf-8");
        //不写编码表名称默认使用IDEA的编码UTF-8
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day16\\utf-8.txt"));
        //2.使用OutputStreamWriter对象中的方法write,把数据写入到内存缓冲区中(字符==>字节)
        osw.write("你好");
        //3.使用OutputStreamWriter对象中的方法flush,把内存缓冲区中的数据刷新到文件中(使用字节输出流把字节写入到文件中)
        osw.flush();
        //4.释放资源(会先调用flush方法刷新数据)
        osw.close();
    }
}

转换文件编码

/*
    练习:转换文件编码
    需求:
        将GBK编码的文本文件,转换为UTF-8编码的文本文件。
    分析:
        1.创建InputStreamReader对象,构造方法中传递FileInputStream对象和GBK编码名称
        2.创建OutputStreamWriter对象,构造方法中传递FileOutputStream对象和UTF-8编码名称
        3.使用InputStreamReader对象中的方法read,读取GBK编码的文件
        4.使用OutputStreamWriter对象中的方法write,把读取的文件以UTF-8编码写入到内存缓冲区中
        5.释放资源(会先调用flush方法刷新数据到文件中)
 */
public class Demo04Test {
    public static void main(String[] args) throws IOException {
        //1.创建InputStreamReader对象,构造方法中传递FileInputStream对象和GBK编码名称
        InputStreamReader isr = new InputStreamReader(new FileInputStream("day16\\gbk.txt"),"gbk");
        //2.创建OutputStreamWriter对象,构造方法中传递FileOutputStream对象和UTF-8编码名称
        //OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day16\\utf-8.txt"),"utf-8");
        //OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day16\\utf-8.txt"));//默认UTF-8编码
        FileWriter osw = new FileWriter("day16\\utf-8.txt");
        //3.使用InputStreamReader对象中的方法read,读取GBK编码的文件
        int len = 0;
        while ((len = isr.read())!=-1){
            //4.使用OutputStreamWriter对象中的方法write,把读取的文件以UTF-8编码写入到内存缓冲区中
            osw.write(len);
        }
        //5.释放资源(会先调用flush方法刷新数据到文件中)
        osw.close();
        isr.close();
    }
}

总结:

什么时候使用FileReader和FileWriter(读取字符的便捷类):读写的文件都是IDEA默认编码utf-8的文件
什么时候使用InputStreamReader和OutputStreamWriter:读写的文件不是IDEA默认编码utf-8的文件

序列化

在这里插入图片描述

ObjectOutputStream: 对象的序列化流(重点)

/*
    java.io.ObjectOutputStream:对象的序列化流 extends OutputStream
    作用:把对象以流的方式写入到文件中保存
    构造方法:
        ObjectOutputStream(OutputStream out) 创建写入指定 OutputStream 的 ObjectOutputStream。
        参数:
           OutputStream out:传递字节输出流,可以传递OutputStream的任意子类对象
    特有的成员方法:
        void writeObject(Object obj) 将指定的对象写入 ObjectOutputStream。
    使用步骤:
        1.创建ObjectOutputStream对象,构造方法中传递FileOutputStream对象
        2.使用ObjectOutputStream对象中的方法writeObject,把对象写入到文件中
        3.释放资源
 */
public class Demo01ObjectOutputStream {
    public static void main(String[] args) throws IOException {
        //1.创建ObjectOutputStream对象,构造方法中传递FileOutputStream对象
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day16\\person.txt"));
        //2.使用ObjectOutputStream对象中的方法writeObject,把对象写入到文件中
        oos.writeObject(new Person("小美女",18));
        //3.释放资源
        oos.close();
    }
}
/*
    在进行序列化和反序列化的时候,会抛出NotSerializableException异常:没有序列化异常
    类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。
        Serializable接口是一个标记型接口,类实现了Serializable接口,接口就会给类添加一个标记
        当我们进行序列化和反序列化的时候,会检查类上是否有标记,有则序列化成功,没有就会抛出NotSerializableException异常
    去市场卖肉==>肉上有一个蓝色的检测合格的章==>放心购买==>买回来肉怎么吃==>炖,炒,做馅...
    类==>有了一个标记==>放心序列化和反序列化了==>类做不做其他的用途不管
 */
public class Person implements Serializable{
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

ObjectInputStream:对象反序列化流(重点)

/*
    java.io.ObjectInputStream:对象的反序列化流 extends InputStream
    作用:把文件中保存的对象以流的方式读取出来使用
    构造方法:
        ObjectInputStream(InputStream in) 创建从指定 InputStream 读取的 ObjectInputStream。
        参数:
           InputStream in:传递字节输入流,可以传递InputStream任意子类对象
    特有的成员方法:
        Object readObject() 从 ObjectInputStream 读取对象。
    实现步骤:
        1.创建ObjectInputStream对象,构造方法中传递FileInputStream对象
        2.使用ObjectInputStream对象中的方法readObject,读取文件中保存的对象
        3.释放资源
    注意:
        readObject方法抛出了两个异常对象
        public final Object readObject()throws IOException, ClassNotFoundException
        ClassNotFoundException:找不到class文件异常
 */
public class Demo02ObjectInputStream {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //1.创建ObjectInputStream对象,构造方法中传递FileInputStream对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day16\\person.txt"));
        //2.使用ObjectInputStream对象中的方法readObject,读取文件中保存的对象
        Object obj = ois.readObject();
        System.out.println(obj);
        //3.释放资源
        ois.close();
    }
}

transient:瞬态关键字

static:静态关键字
    静态优先于非静态加载到内存中
    序列化的是对象,如果成员变量被static修饰,不能被序列化的
    private static int age;
    oos.writeObject(new Person("小美女",18));
    Object obj = ois.readObject();
    Person{name='小美女', age=0}

transient:瞬态关键字
    被transient关键字修饰的变量不能被序列化
    private transient int age;
    oos.writeObject(new Person("小美女",18));
    Object obj = ois.readObject();
    Person{name='小美女', age=0}
java中:
    ArrayList集合底层是一个不能被序列化的数组
    transient Object[] elementData;

序列号冲突异常(重点)

在这里插入图片描述

public class Person implements Serializable{
    /*
        序列化类可以通过声明名为 "serialVersionUID" 的字段(
        该字段必须是静态 (static)、最终 (final) 的 long 型字段)
        显式声明其自己的 serialVersionUID:
        static final long serialVersionUID = 42L;
        手动添加完序列号,无论是否怎么修改,序列号都固定为写的常量的值,不会改变,也就不会抛出异常
        java.lang.String类
            public final class String implements java.io.Serializable
            private static final long serialVersionUID = -6849794470754667710L;
     */
    private static final long serialVersionUID = 1L;
    private String name;
    //private static int age;
    //private transient int age;
    public int age;
}

装饰模式(重点)

/*
    定义顶层手机类
 */
public abstract class Phone {
    public abstract void call();
    public abstract void sendMessage();
}
public class FirstPhone extends Phone {
    @Override
    public void call() {
        System.out.println("使用手机打电话!");
    }

    @Override
    public void sendMessage() {
        System.out.println("使用手机发短信!");
    }
}
public class SecondPhone extends Phone {
    @Override
    public void call() {
        System.out.println("使用手机打电话!");
    }

    @Override
    public void sendMessage() {
        System.out.println("使用手机发短信!");
    }
}
/*
    手机的装饰者类
        把手机传递到类中,对手机进行装饰
        传递进来手机对象==>使用构造方法
 */
public class PhoneWapper extends Phone{
    //定义一个手机变量
    private Phone phone;

    public PhoneWapper(Phone phone) {
        this.phone = phone;
    }

    @Override
    public void call() {
        //对打电话功能进行装饰
        System.out.println("打电话之前听彩铃!");
        phone.call();
    }

    @Override
    public void sendMessage() {
        //发短信的功能不变
        phone.sendMessage();
    }
}
/*
    装饰者模式:
    设计一个手机类
        打电话功能
        发短信功能
    需求变更:
        对打电话的功能进行增强,打电话之前听彩铃
        但是有人喜欢彩铃,有人不喜欢
        就不能在打电话的功能上进行修改,一旦修改了所有的人都必须听彩铃
    所以我们就可以使用装饰者设计模式
        对手机进行装饰,让喜欢听彩铃的人打电话之前先听彩铃
        使用装饰模式的手机==> 打电话之前先听彩铃
        没有使用装饰模式的手机==> 打电话的功能不变
 */
public class Demo01Wapper {
    public static void main(String[] args) throws IOException {
        //创建FirstPhone对象,不使用装饰者模式
        FirstPhone fp1 = new FirstPhone();
        fp1.call();
        fp1.sendMessage();
        System.out.println("----------------------");
        //创建手机的装饰者对象,传递FirstPhone手机对象,对手机的打电话进行装饰
        PhoneWapper pw = new PhoneWapper(fp1);
        pw.call();
        pw.sendMessage();
        System.out.println("----------------------");
        //创建手机的装饰者对象,传递SecondPhone手机对象,对手机的打电话进行装饰
        PhoneWapper pw2 = new PhoneWapper(new SecondPhone());
        pw2.call();
        pw2.sendMessage();
        System.out.println("----------------------");
        //java中多处地方都采用了装饰者设计模式
        FileReader fr = new FileReader("day11\\1.txt");
        int len = fr.read();//一次读取一个字符效率低下

        //BufferedReader就是一个装饰者类,给FileReader增加了一个缓冲区,提高FileReader读取文件的效率
        BufferedReader br =new BufferedReader(fr);
        br.read();//把读取到的字节存储到内存缓冲区中,一次性写回,效率高
    }
}

装饰模式小结

装饰模式可以在不改变原类的基础上对类中的方法进行扩展增强,实现原则为:

  1. 装饰类和被装饰类必须实现相同的接口,继承相同的父类
  2. 在装饰类中必须传入被装饰类的引用,使用构造方法传递
  3. 在装饰类中对需要扩展的方法进行扩展
  4. 在装饰类中对不需要扩展的方法调用被装饰类中的同名方法

Commons-io工具包

概述

commons-io是apache开源基金组织提供的一组有关IO操作的类库,可以挺提高IO功能开发的效率。commons-io工具包提供了很多有关io操作的类,见下表:

在这里插入图片描述

添加第三方jar包到模块中(重点)

步骤:

  1. 下载commons-io相关jar包: http://commons.apache.org/proper/commons-io/
  2. 把commons-io-2.6.jar包复制到指定的Module的lib目录中
    在这里插入图片描述
  3. 将commons-io-2.6.jar加入到classpath中
    在这里插入图片描述

IOUtils工具类基本使用(重中之重)

/*
    org.apache.commons.io.IOUtils:操作IO流的工具类
        1. public static int copy(InputStream in, OutputStream out);
            把input输入流中的内容拷贝到output输出流中,返回拷贝的字节个数(适合文件大小为2GB以下)
        2. public static long copyLarge(InputStream in, OutputStream out);
            把input输入流中的内容拷贝到output输出流中,返回拷贝的字节个数(适合文件大小为2GB以上)
 */
public class Demo01IOUtils {
    public static void main(String[] args) throws IOException {
        //使用IOUtils工具类中的静态方法copy复制一个文件
        //int fileSize = IOUtils.copy(new FileInputStream("c:\\1.jpg"), new FileOutputStream("d:\\1.jpg"));
        //System.out.println(fileSize);//36418 字节

        //使用IOUtils工具类中的静态方法copyLarge复制一个大文件
        long fileSize2 = IOUtils.copyLarge(new FileInputStream("c:\\748m.rar"), new FileOutputStream("d:\\748m.rar"));
        System.out.println(fileSize2);//785042177 字节
    }
}

FileUtils工具类基本使用(重中之重)

/*
    org.apache.commons.io.FileUtils:操作文件的工具类
        static String 	readFileToString(File file) 读取一个文件以字符串的方式返回
        static void 	writeStringToFile(File file, String data) 把字符串写到一个文件中
        static void 	copyFile(File srcFile, File destFile) 文件复制
        static void 	copyFileToDirectory(File srcFile, File destDir) 把一个文件复制到另外一个文件夹中
        static void 	copyDirectoryToDirectory(File srcDir, File destDir) 文件夹复制
   注意:
        以上5个方法参数都是File对象
 */
public class Demo02FileUtils {
    public static void main(String[] args) throws IOException {
        show05();
    }

    /*
        static void 	copyDirectoryToDirectory(File srcDir, File destDir) 文件夹复制
     */
    private static void show05() throws IOException {
        FileUtils.copyDirectoryToDirectory(new File("c:\\demo"),new File("d:\\"));
    }

    /*
        static void 	copyFileToDirectory(File srcFile, File destDir) 把一个文件复制到另外一个文件夹中
     */
    private static void show04() throws IOException {
        FileUtils.copyFileToDirectory(new File("c:\\1.jpg"),new File("d:\\aaa"));
    }

    /*
        static void 	copyFile(File srcFile, File destFile) 文件复制
     */
    private static void show03() throws IOException {
        FileUtils.copyFile(new File("c:\\1.jpg"),new File("d:\\1.jpg"));
    }

    /*
        static void 	writeStringToFile(File file, String data) 把字符串写到一个文件中
     */
    private static void show02() throws IOException {
        FileUtils.writeStringToFile(new File("day16\\fileUtils.txt"),"哈哈,呵呵,嘿嘿");
    }

    /*
        static String 	readFileToString(File file) 读取一个文件以字符串的方式返回
     */
    private static void show01() throws IOException {
        String s = FileUtils.readFileToString(new File("c:\\Demo01BufferedInputStream.java"));
        System.out.println(s);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值