[java入门到精通] 18 字符流,编码表,对象流,其他流

今日目标

1 编码表

1.1 思考:

  • 既然字节流可以操作所有文件,那么为什么还要学习字符流 ?
    • 如果使用字节流 , 把文本文件中的内容读取到内存时, 可能会出现乱码
    • 如果使用字节流 , 把中文写入文本文件中 , 也有可能会出现乱码

1.2 编码表介绍

  • 计算机中储存的信息都是用二进制数据表示的;我们在屏幕上看到的英文、汉字等字符是二进制数转换之后的结果

  • 按照编码表规则,将字符存储到计算机中,称为编码。

  • 按照同样的编码表规则,将存储在计算机中的二进制数据解析显示出来,称为解码 。

  • 编码和解码使用的码表必须一致,否则会导致乱码。

  • 简单理解:
    • 存储一个字符a,首先需在码表中查到对应的数字是97,然后按照转换成二进制的规则进行存储。称为编码
    • 读取的时候,先把二进制解析出来,再转成97,通过97查找早码表中对应的字符是a。称为解码
  • ASCII码表:
    • ASCII(American Standard Code for Information Interchange,美国信息交换标准码表):
    • 包括了数字字符,英文大小写字符和一些常见的标点符号字符。
    • 注意:ASCII码表中是没有中文的。
  • GBK码表:
    • window系统默认的码表。兼容ASCII码表,也包含了21003个汉字,并支持繁体汉字以及部分日韩文字
    • 注意:GBK是中国的码表,一个中文以两个字节的形式存储。但不包含世界上所有国家的文字。
  • Unicode码表:
    • 由国际组织ISO 制定,是统一的万国码表,计算机科学领域里的一项业界标准,容纳世界上大多数国家的所有常见文字和符号。
    • 但是因为表示的字符太多,所以Unicode码表中的数字不是直接以二进制的形式存储到计算机的,会先通过UTF-7,UTF-7.5,UTF-8,UTF-16,以及 UTF-32的编码方式再存储到计算机,其中最为常见的就是UTF-8。
    • 注意: Unicode是万国码表,以UTF-8编码后一个中文以三个字节的形式存储

2 字符输出流

2.1 字符流输出介绍

  • Writer类
    • 写入字符流的最顶层的类 , 是一个抽象类 ,不能实例化 , 需要使用其子类FileWriter类
  • FileWriter类 : 用来写入字符文件的便捷类

2.2 FileWriter的成员

  • 构造方法 :

    • public FileWriter(File file) : 往指定的File路径中写入数据
    • public FileWriter(String fileName) : 往指定的String路径中写入数据
  • 成员方法 :

    • void write(int c)写一个字符
      void write(char[] cbuf)写入一个字符数组
      void write(char[] cbuf, int off, int len)写入字符数组的一部分
      void write(String str)写一个字符串
      void write(String str, int off, int len)写一个字符串的一部分
    • flush()刷新流,还可以继续写数据
      close()关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据

2.3 FileWriter写数据的步骤

  • 1 创建字符输出流对象
    • 注意事项:
      如果文件不存在,就创建。但是要保证父级路径存在。
      如果文件存在就清空
  • 2 写数据
    • 注意事项:
      写出int类型的整数,实际写出的是整数在码表上对应的字母。
      写出字符串数据,是把字符串本身原样写出。
  • 3 释放资源
    • 注意事项:
      每次使用完流必须要释放资源。
  • package com.lystar.writer_demo;
    
    import java.io.FileWriter;
    import java.io.IOException;
    
    /*
        Writer类 : 写入字符流的最顶层的类 , 是一个抽象类 ,不能实例化
        需要使用其子类FileWriter类
    
        FileWriter类 : 用来写入字符文件的便捷类
        构造方法 :
            public FileWriter(File file) : 往指定的File路径中写入数据
            public FileWriter(String fileName) : 往指定的String路径中写入数据
        成员方法
            void write​(int c)	写一个字符
            void write​(char[] cbuf)	写入一个字符数组
            void write​(char[] cbuf, int off, int len)	写入字符数组的一部分
            void write​(String str)	写一个字符串
            void write​(String str, int off, int len)	写一个字符串的一部分
            flush()	刷新流,还可以继续写数据
            close()	关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据
     */
    public class WriterDemo1 {
        public static void main(String[] args) throws IOException {
            // 创建字符输出流对象
            // 如果文件不存在会创建一个空的文件
            // 如果文件存在 , 会把文件中的内容清空
            FileWriter fw = new FileWriter("day12_demo\\charstream2.txt");
    
            // 写数据
            fw.write('a');
            fw.write('b');
            // 刷新流 , 把流中的数据刷到硬盘中 , 刷新之后可以继续写数据
            // fw.flush();
    
            // 释放资源
            // 关闭流 , 但是会先刷新流
            fw.close();
            // 一旦关闭流无法写数据
            // fw.write('c');
        }
    }
    
    
    package com.lystar.writer_demo;
    
    import java.io.FileWriter;
    import java.io.IOException;
    
    /*
        Writer类 : 写入字符流的最顶层的类 , 是一个抽象类 ,不能实例化
        需要使用其子类FileWriter类
    
        FileWriter类 : 用来写入字符文件的便捷类
        构造方法 :
            public FileWriter(File file) : 往指定的File路径中写入数据
            public FileWriter(String fileName) : 往指定的String路径中写入数据
        成员方法
            void write​(int c)	写一个字符
            void write​(char[] cbuf)	写入一个字符数组
            void write​(char[] cbuf, int off, int len)	写入字符数组的一部分
            void write​(String str)	写一个字符串
            void write​(String str, int off, int len)	写一个字符串的一部分
            flush()	刷新流,还可以继续写数据
            close()	关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据
     */
    public class WriterDemo2 {
        public static void main(String[] args) throws IOException {
            // 创建字符输出流对象
            FileWriter fw = new FileWriter("day12_demo\\charstream2.txt");
    
            // 写数据
    //        void write​(int c)	写一个字符
    //        fw.write('a');
    //        fw.write('b');
    //        fw.write('c');
    
    //        void write​(char[] cbuf)	写入一个字符数组
            char[] chs = {'a', 'b', 'c', 'd', 'e'};
    //        fw.write(chs);
    
    //        void write​(char[] cbuf, int off, int len)	写入字符数组的一部分
    //        fw.write(chs , 2 , 3);
    
    //        void write​(String str)	写一个字符串
    //        fw.write("abcadaasda");
    
    //        void write​(String str, int off, int len)	写一个字符串的一部分
    //        fw.write("abnacna", 3, 2);
    
            // 释放资源
            fw.close();
        }
    }
    
    

2.4 字符输出流练习

  • package com.lystar.writer_demo;
    
    import java.io.FileWriter;
    import java.io.IOException;
    import java.util.Scanner;
    
    /*
        需求 : 将用户键盘录入的用户名和密码保存到本地实现永久化存储。
        要求 : 用户名和密码在文件中各占一行
    
        步骤:
            1 用户键盘录入用户名
            2 创建字符输出流对象
            3 将用户名和密码写到本地文件中
     */
    public class WriterTest {
        public static void main(String[] args) throws IOException {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入用户名:");
            String username = sc.nextLine();
    
            System.out.println("请输入密码:");
            String password = sc.nextLine();
    
            // 创建字符输出流对象
            FileWriter fw = new FileWriter("day12_demo\\user.txt");
            // 往文件中写入用户名和密码
            fw.write(username);
            // 换行
            fw.write("\r\n");
            fw.write(password);
            // 刷新
            fw.flush();
            // 释放资源
            fw.close();
        }
    }
    
    

3 字符输入流

3.1 字节输入流介绍

  • Reader类 :
    • 读取字符流的最顶层的类 , 是一个抽象类 ,不能实例化
    • 需要使用其子类FileReader类
  • FileReader类 :
    • 用来读取字符文件的便捷类

3.2 FileReader的成员

  • 构造方法 :

    • public FileReader(File file) : 从指定的File路径中读取数据
    • public FileReader(String fileName) : 从指定的String路径中读取数据
  • 成员方法 :

    • int read()一次读一个字符数据
      int read(char[] cbuf)一次读一个字符数组数据
  • package com.lystar.reader_demo;
    
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.IOException;
    
    /*
        Reader类 : 读取字符流的最顶层的类 , 是一个抽象类 ,不能实例化
        需要使用其子类FileReader类
    
        FileReader类 : 用来读取字符文件的便捷类
    
        构造方法 :
            public FileReader(File file) : 从指定的File路径中读取数据
            public FileReader(String fileName) : 从指定的String路径中读取数据
    
        成员方法 :
            int read​() : 一次读一个字符数据
            int read​(char[] cbuf)	 : 一次读一个字符数组数据
     */
    public class ReaderDemo1 {
        public static void main(String[] args) throws IOException {
            // 创建字符输入流对象
            FileReader fr = new FileReader("day12_demo\\charstream.txt");
    
            // 一次读一个字符数据
            int ch;
            while ((ch = fr.read()) != -1) {
                System.out.print((char) ch);
            }
    
            // 释放资源
            fr.close();
        }
    }
    
    
  • package com.lystar.reader_demo;
    
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.IOException;
    
    /*
        Reader类 : 读取字符流的最顶层的类 , 是一个抽象类 ,不能实例化
        需要使用其子类FileReader类
    
        FileReader类 : 用来读取字符文件的便捷类
    
        构造方法 :
            public FileReader(File file) : 从指定的File路径中读取数据
            public FileReader(String fileName) : 从指定的String路径中读取数据
    
        成员方法 :
            int read​()	一次读一个字符数据
            int read​(char[] cbuf)	一次读一个字符数组数据
     */
    public class ReaderDemo2 {
        public static void main(String[] args) throws IOException {
            // 创建字符输入流对象
            FileReader fr = new FileReader("day12_demo\\charstream.txt");
    
            // 一次读一个字符数组数据
            char[] chs = new char[1024];
            int len;
            while ((len = fr.read(chs)) != -1) {
                System.out.println(new String(chs, 0, len));
            }
            // 释放资源
            fr.close();
        }
    }
    
    

4 字符缓冲流

4.1 字符缓冲流

  • BufferedWriter:可以将数据高效的写出
  • BufferedReader:可以将数据高效的读入到内存
  • 注意 : 字符缓冲流不具备读写功能 , 只提供缓冲区 , 真正读写还是需要依赖于构造接收的基本的字符流
  • 构造方法:
    • public BufferedWriter(Writer out) : 构造方法中需要接收一个基本的字符输出流
    • public BufferedReader(Reader in) : 构造方法中需要接收一个基本的字符输入流
package com.lystar.bufferedstream_demo;

import java.io.*;

/*
    需求 : 使用字符缓冲流复制纯文本文件
    将当日课程资料中的 ‘斗罗大陆.txt’ 复制到当前模块下 'copy.txt'
 */
public class BufferedStreamDemo1 {
    public static void main(String[] args) throws IOException {
        // 创建高效的字符输入流对象
        BufferedReader br = new BufferedReader(new FileReader("D:\\develop\\text\\01.txt"));
        // 创建高效的字符输出流对象
        BufferedWriter bw = new BufferedWriter(new FileWriter("copy\\copy.txt"));

        // 一次读写一个字符
//        int ch;
//        while ((ch = br.read()) != -1) {
//            bw.write(ch);
//        }

        // 一次读写一个字符数组
        char[] chs = new char[1024];
        int len;
        while ((len = br.read(chs)) != -1) {
            bw.write(chs, 0, len);
        }
        // 释放资源
        br.close();
        bw.close();
    }
}

4.2 字符缓冲流特有的功能

  • BufferedWriter类
    • void newLine():写一个行分隔符,会根据操作系统的不同,写入不同的行分隔符
  • BufferedReader类
    • public String readLine() :读取文件一行数据, 不包含换行符号 , 读到文件的末尾返回null
  • package com.lystar.bufferedstream_demo;
    
    import java.io.*;
    
    /*
        1 字符缓冲流:
            BufferedWriter:可以将数据高效的写出
            BufferedReader:可以将数据高效的读入到内存
    
        2 字符缓冲流特有功能
            BufferedWriter类
                void newLine​():写一个行分隔符,会根据操作系统的不同,写入不同的行分隔符
            BufferedReader类
                public String readLine​() :读取文件一行数据, 不包含换行符号 ,  读到文件的末尾返回null
    
     */
    public class BufferedStreamDemo2 {
        public static void main(String[] args) throws IOException {
    
            // 创建高效的字符输出流对象
            BufferedWriter bw = new BufferedWriter(new FileWriter("day12_demo\\abc.txt"));
            // void newLine​():写一个行分隔符,会根据操作系统的不同,写入不同的行分隔符
            bw.write("锄禾日当午");
            bw.newLine();
            bw.write("汗滴禾下土");
            bw.newLine();
            bw.write("谁知盘中餐");
            bw.newLine();
            bw.write("粒粒皆辛苦");
            bw.flush();
    
            // 创建高效的字符输入流对象
            BufferedReader br = new BufferedReader(new FileReader("day12_demo\\abc.txt"));
            // public String readLine​() :读取文件一行数据, 不包含换行符号 ,  读到文件的末尾返回null
    //        String s = br.readLine();
    //        System.out.println(s);
    //        s = br.readLine();
    //        System.out.println(s);
    //        s = br.readLine();
    //        System.out.println(s);
    //        s = br.readLine();
    //        System.out.println(s);
    //        System.out.println("============");
    //        s = br.readLine();
    //        System.out.println(s);
    //        s = br.readLine();
    //        System.out.println(s);
    
            // 循环改进
            String line;
            while((line = br.readLine()) != null){
                System.out.println(line);
            }
    
            // 释放资源
            br.close();
            bw.close();
        }
    }
    
    

4.3 字符缓冲流练习

package com.lystar.bufferedstream_demo;

import java.io.*;
import java.util.Arrays;

/*
    需求:读取文件中的数据 : 33 22 11 55 44
    排序后 : 11 22 33 44 55  再次写到本地文件

    步骤 :
        1 创建高效的字符输入流对象
        2 读取文件中的一行数据
        3 将数据按照空格切割
        4 把字符串数组转成int类型数组
        5 对int类型的数组进行排序
        6 创建高效的字符输出流对象
        7 遍历数组,把数组中的数据写入到文件中
        8 释放资源
 */
public class BufferedStreamDemo3 {
    public static void main(String[] args) throws IOException {
        // 1 创建高效的字符输入流对象
        BufferedReader br = new BufferedReader(new FileReader("day12_demo\\sort.txt"));
        // 2 读取文件中的一行数据
        String line = br.readLine();
        // 3 将数据按照空格切割
        String[] strs = line.split(" ");
        // 4 把字符串数组转成int类型数组
        int[] arr = new int[strs.length];
        for (int i = 0; i < strs.length; i++) {
            arr[i] = Integer.parseInt(strs[i]);
        }
        // 5 对int类型的数组进行排序
        Arrays.sort(arr);
        // 6 创建高效的字符输出流对象
        BufferedWriter bw = new BufferedWriter(new FileWriter("day12_demo\\sort.txt"));
        // 7 遍历数组,把数组写入到文件中
        for (int i = 0; i < arr.length; i++) {
            bw.write(arr[i] + " ");
            bw.flush();
        }
        // 8 释放资源
        br.close();
        bw.close();
    }
}

5 转换流

5.1 转换流介绍

  • 转换流就是来进行字节流和字符流之间转换的桥梁

5.2 转换流分类

  • InputStreamReader是从字节流到字符流的桥梁

    • public InputStreamReader(InputStream in) : 创建一个使用默认编码的 InputStreamReader。
    • public InputStreamReader(InputStream in , String charsetName) : 创建使用指定编码的 InputStreamReader。
  • OutputStreamWriter是从字符流到字节流的桥梁

    • public OutputStreamWriter(OutputStream out) : 创建使用默认字符编码的 OutputStreamWriter
    • public OutputStreamWriter(OutputStream out, String charsetName) : 创建使用指定编码的 OutputStreamWriter。
  • 练习
    package com.lystar.conversion_demo;
    
    import java.io.*;
    
    /*
        转换流就是来进行字节流和字符流之间转换的桥梁
    
        InputStreamReader是从字节流到字符流的桥梁
            public InputStreamReader(InputStream in) : 创建一个使用默认编码的 InputStreamReader。
            public InputStreamReader(InputStream in ,  String charsetName) : 创建使用指定编码的 InputStreamReader。
    
        OutputStreamWriter是从字符流到字节流的桥梁
            public OutputStreamWriter(OutputStream out) : 创建使用默认字符编码的 OutputStreamWriter
            public OutputStreamWriter(OutputStream out,  String charsetName) : 创建使用指定编码的 OutputStreamWriter。
    
    
        需求1 : 使用转换流 , 把以下数据按照GBK的编码写入文件 , 在使用GBK的编码读取数据
     */
    public class ConversionDemo2 {
        public static void main(String[] args) throws IOException {
            // 创建转换输出流
            OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day12_demo\\conversion.txt"), "GBK");
            osw.write("床前明月光");
            osw.write("\r\n");
            osw.write("疑似地上霜");
            osw.write("\r\n");
            osw.write("举头望明月");
            osw.write("\r\n");
            osw.write("低头思故乡");
            osw.write("\r\n");
            osw.close();
    
            // 创建转换输入流
            InputStreamReader isr = new InputStreamReader(new FileInputStream("day12_demo\\conversion.txt"), "GBK");
            int ch;
            while ((ch = isr.read()) != -1) {
                System.out.print((char) ch);
            }
            isr.close();
        }
    }
    
    
    package com.lystar.conversion_demo;
    
    import java.io.*;
    
    /*
        转换流就是来进行字节流和字符流之间转换的桥梁
    
        InputStreamReader是从字节流到字符流的桥梁
            public InputStreamReader(InputStream in) : 创建一个使用默认编码的 InputStreamReader。
            public InputStreamReader(InputStream in ,  String charsetName) : 创建使用指定编码的 InputStreamReader。
    
        OutputStreamWriter是从字符流到字节流的桥梁
            public OutputStreamWriter(OutputStream out) : 创建使用默认字符编码的 OutputStreamWriter
            public OutputStreamWriter(OutputStream out,  String charsetName) : 创建使用指定编码的 OutputStreamWriter。
    
        需求2 :  将模块根目录中GBK编码的文本文件 , 转换为UTF-8编码的文本文件
     */
    public class ConversionDemo2 {
        public static void main(String[] args) throws IOException {
    
            // 创建转换输入流
            InputStreamReader isr = new InputStreamReader(new FileInputStream("day12_demo\\GBK编码的文件.txt"), "GBK");
    
            // 创建转换输出流
            OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day12_demo\\UTF编码的文件.txt"), "UTF-8");
    
            int ch;
            while ((ch = isr.read()) != -1) {// 以GBK编码进去读取
                osw.write(ch);// 以UTF-8编码进行写入
            }
    
            // 释放资源
            isr.close();
            osw.close();
        }
    }
    
    

6 对象操作流

6.1 对象操作流介绍

  • 可以把对象以字节的形式写到本地文件,直接打开文件,是读不懂的,需要再次用对象操作流读到内存中

6.2 对象操作流的分类

  • ObjectOutputStream :
    • ​ 对象操作输出流(对象序列化流):就是将对象写到本地文件中,或者在网络中传输对象
  • ObjectInputStream :
    • ​ 对象操作输入流(对象反序列化流):把写到本地文件中的对象读到内存中,或者接收网络中传输的对象

6.3 对象操作流的注意事项

  • 注意 : 如果一个类对象想要被序列化 , 那么此类需要实现Serializable接口

    • Serializable接口的含义 :
      • ​ 1 是一个标记性接口 , 里面没有任何抽象方法
      • ​ 2 只要一个类实现了此接口 , 表示此类的对象可以被序列化
  • 用对象序列化流序列化了一个对象后,假如我们修改了对象所属的Javabean类,读取数据会不会出问题呢?

    • 会出问题,会抛出InvalidClassException异常
  • 如果出问题了,如何解决呢?

    • 给对象所属的类加一个serialVersionUID
    • private static final long serialVersionUID = 42L;
  • 如果一个对象中的某个成员变量的值不想被序列化,又该如何实现呢?

  • 给该成员变量加transient关键字修饰,该关键字标记的成员变量不参与序列化过程

  • package com.lystar.objectstream_demo;
    
    
    import java.io.Serializable;
    
    /*
        如果此类对象想要被序列化 , 那么此类需要实现Serializable接口
        Serializable接口的含义 :
            是一个标记性接口 , 里面没有任何抽象方法
            只要一个类实现了此接口 , 表示此类的对象可以被序列化
     */
    public class User implements Serializable {
        /*
            问题分析 :
                serialVersionUID : 序列号
                序列号是根据类的信息进行生成的
                如果没有自己给出序列号 , JVM会根据类的信息自动计算一个序列号
                如果改动了类的信息 , 那么JVM会重新计算一个序列号
    
                第一步 : 把对象序列化到本地中 , 序列号为 -4446663370728791812 也会存储到本地中
                第二步 : 我们自己修改了类 , 会重新计算一个新的序列号 2908680347500030933
                第三步 : 当把对象读到内存中时 , 本地中的序列号和类中的序列号不一致就会发生 InvalidClassException异常
    
            解决方案 :
                我们自己手动给出序列号, 不让虚拟机自动生成 , 并且这个值恒久不变
                private static final long serialVersionUID = 值L;
         */
    
        private static final long serialVersionUID = 111L;
    
        private String username;
        private transient String password;
    
        public User() {
        }
    
        public User(String username, String password) {
            this.username = username;
            this.password = password;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "username='" + username + '\'' +
                    ", password='" + password + '\'' +
                    '}';
        }
    }
    

6.4 对象操作流的练习

7 装饰设计模式

  • 设计模式 : 一套良好的编码风格 , 经过众多的开发人员不断的测试总结而来
学习目标
  • 熟悉装饰设计模式的使用
内容讲解
【1】概述
  • 装饰模式指的是在不改变原类, 不使用继承的基础上,动态地扩展一个对象的功能。

  • 不使用继承技术扩展功能, 可以降低耦合

  • 使用原则:
    • 装饰类和被装饰类需要有共同的父类型。
      • 在之前学习过的 BufferedWriter 和 FileWriter 就是装饰设计模式
      • BufferedWriter的父类为Writer
      • FileWriter的父类也是Writer
      • 我们把FileWriter的对象传递到BufferedWriter的构造中 , 那么可以理解为BufferedWriter是装饰类 , FileWriter是被装饰类
      • BufferedWriter对FileWriter的功能做了增强
    • 装饰类的构造要接收被装饰类的对象
      • FileWriter fw = new FileWriter(“路径”);
      • BufferedWriter bw = new BufferedWriter(fw);
    • 在装饰类中把要增强扩展的功能进行扩展
      • BufferedWriter和FileWriter的功能一样, 都具备Writer中写数据的功能
      • 但是BufferedWriter提供了缓冲区 , 相当于对FileWriter功能做了扩展
    • 对于不要增强的功能直接调用
      • 不需要增强的功能直接继承父类的即可
【2】代码实践

已知有接口Star和其子类型LiuDeHua。

public interface Star {
    public abstract void sing();
    public abstract void dance();
}

需求 :在不改变LiuDeHua类,及不使用继承的技术前提下,动态的扩展LiuDeHua的sing功能。

LiuDeHua就是一个被装饰类 , 需要对唱歌的功能进行扩展

思路 :

定义一个装饰类,去装饰增强 LiuDehua类。

步骤:

  • 创建LiuDeHua类并实现接口Star【被装饰类】

  • 定义一个装饰类LiuDeHuaWrapper实现Star 【装饰类】

  • 在装饰类里面定义一个成员变量类型是LiuDeHua,可以使用构造方法进行传入被装饰类对象。

  • 在装饰类中对sing方法进行功能扩展

  • 对dance不做改动

  • 测试类分别创建装饰类的对象和被装饰类的对象。将被装饰类对象刘德华对象设置给装饰类对象

package com.lystar.design_demo;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;

/*
    装饰模式指的是在不改变原类, 不使用继承的基础上,动态地扩展一个对象的功能

    使用原则 :
        1. 装饰类和被装饰类需要有共同的父类型。
        2. 装饰类要传入被装饰类的对象
        3. 在装饰类中把要增强扩展的功能进行扩展
        4. 对于不要增强的功能直接调用


    需求 : 在不改变LiuDeHua类,及不使用继承的技术前提下,动态的扩展LiuDeHua的sing功能。
            LiuDeHua就是一个被装饰类 , 需要对唱歌的功能进行扩展
    步骤:
        1. 创建LiuDeHua类并实现接口Star【被装饰类】
        2. 定义一个装饰类LiuDeHuaWrapper实现Star 【装饰类】
        3. 在装饰类里面定义一个成员变量类型是LiuDeHua,可以使用构造方法进行传入被装饰类对象。
        4. 在装饰类中对sing方法进行功能扩展
        5. 对dance不做改动
        6. 测试类分别创建装饰类的对象和被装饰类的对象。将被装饰类对象刘德华对象设置给装饰类对象
 */
public class Test {
    public static void main(String[] args) throws IOException {
        // 被装饰类对象
        LiuDeHua huaZai = new LiuDeHua();// 0x001

        // 装饰类对象
        LiuDeHuaWrapper liuDeHuaWrapper = new LiuDeHuaWrapper(huaZai);
        liuDeHuaWrapper.sing();
        liuDeHuaWrapper.dance();

//        // 被装饰类对象
//        FileWriter fw = new FileWriter("路径");
//        // 装饰类对象
//        BufferedWriter bw = new BufferedWriter(fw);
    }
}


// 1. 创建LiuDeHua类并实现接口Star【被装饰类】
class LiuDeHua implements Star {

    @Override
    public void sing() {
        System.out.println("唱忘情水...");
    }

    @Override
    public void dance() {
        System.out.println("华仔在跳老年迪斯高..");
    }
}

// 2. 定义一个装饰类LiuDeHuaWrapper实现Star 【装饰类】
class LiuDeHuaWrapper implements Star {
    // 3. 在装饰类里面定义一个成员变量类型是LiuDeHua,可以使用构造方法进行传入被装饰类对象。
    private LiuDeHua huaZai;// 0x001

    public LiuDeHuaWrapper(LiuDeHua huaZai) {// 0x001
        this.huaZai = huaZai;
    }

    @Override
    public void sing() {
        // 4. 在装饰类中对sing方法进行功能扩展
        System.out.print("华仔深情");
        huaZai.sing();
    }

    @Override
    public void dance() {
        // 5. 对dance不做改动
        huaZai.dance();
    }
}


// 明星接口 , 装饰类和被装饰类的父类型
interface Star {
    public abstract void sing(); // 唱歌

    public abstract void dance();// 跳舞
}
内容小结
  1. 装饰类和被装饰类需要有共同的父类型。
  2. 装饰类要传入被装饰类的对象
  3. 在装饰类中把要增强扩展的功能进行扩展
  4. 对于不要增强的功能直接调用

9 commons-io工具包(对文件的拷贝做优化)

学习目标
  • 能够熟悉导入commons-io工具包,并使用
内容讲解
【1】三方库的导入
  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加入到项目中

    右键jar包:

    在这里插入图片描述
    在这里插入图片描述

【2】API

1)org.apache.commons.io.IOUtils类

public static int copy(InputStream in, OutputStream out):
	把input输入流中的内容拷贝到output输出流中,返回拷贝的字节个数(适合文件大小为2GB以下)
    
public static long copyLarge(InputStream in, OutputStream out):
	把input输入流中的内容拷贝到output输出流中,返回拷贝的字节个数(适合文件大小为2GB以上)

package com.lystar.commons_io;

import org.apache.commons.io.IOUtils;

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

/*
    org.apache.commons.io.IOUtils类

    public static int copy(InputStream in, OutputStream out):
	把input输入流中的内容拷贝到output输出流中,返回拷贝的字节个数(适合文件大小为2GB以下)

    public static long copyLarge(InputStream in, OutputStream out):
	把input输入流中的内容拷贝到output输出流中,返回拷贝的字节个数(适合文件大小为2GB以上)
 */
public class Test1 {
    public static void main(String[] args) throws IOException {
        IOUtils.copy(new FileInputStream("D:\\develop\\img\\03.jpg") , new FileOutputStream("test\\copy.jpg"));
    }
}

2)org.apache.commons.io.FileUtils

public static void copyFileToDirectory(final File srcFile, final File destFile): 
	复制文件到另外一个目录下。
public static void copyDirectoryToDirectory(File src , File dest ):
	复制src目录到dest位置。

代码实践:

package com.lystar.commons_io;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;

/*
    org.apache.commons.io.FileUtils

    public static void copyFileToDirectory(final File srcFile, final File destFile):
	复制文件到另外一个目录下。

    public static void copyDirectoryToDirectory(File src , File dest ):
	复制src目录到dest目录中。
 */
public class Test2 {
    public static void main(String[] args) throws IOException {
        FileUtils.copyDirectoryToDirectory(new File("D:\\develop\\img\\01.jpg") , new File("D:\\"));
    }
}

内容小结

代码实践:

package com.lystar.commons_io;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;

/*
    org.apache.commons.io.FileUtils

    public static void copyFileToDirectory(final File srcFile, final File destFile):
	复制文件到另外一个目录下。

    public static void copyDirectoryToDirectory(File src , File dest ):
	复制src目录到dest目录中。
 */
public class Test2 {
    public static void main(String[] args) throws IOException {
        FileUtils.copyDirectoryToDirectory(new File("D:\\develop\\img\\02.jpg") , new File("D:\\"));
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/445401.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ODP(Open Data Plane)

1. 摘要 本文档旨在指导新的ODP应用程序开发人员。 有关ODP的更多详细信息&#xff0c;请参见 ODP 主页。 Overview of a system running ODP applications ODP是一份API规范&#xff0c;为高性能网络应用程序的实现提供平台独立性、自动硬件加速和CPU扩展。 本文档介绍如何充…

DHCP中继实验(思科)

华为设备参考&#xff1a;DHCP中继实验&#xff08;华为&#xff09; 一&#xff0c;技术简介 DHCP中继&#xff0c;可以实现在不同子网和物理网段之间处理和转发DHCP信息的功能。如果DHCP客户机与DHCP服务器在同一个物理网段&#xff0c;则客户机可以正确地获得动态分配的IP…

OS-Copilot:实现具有自我完善能力的通用计算机智能体

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ AI 缩小了人类间的知识和技术差距 论文标题&#xff1a;OS-Copilot: Towards Generalist Computer Agents with Self-Improvement 论文链接&#xff1a;https://arxiv.org/abs/2402.07456 项目主页&a…

Hadoop生态选择(一)

一、项目框架 1.1技术选型 技术选型主要考虑因素:维护成本、总成本预算、数据量大小、业务需求、行业内经验、技术成熟度。 数据采集传输:Flume&#xff0c;Kafka&#xff0c;DataX&#xff0c;Maxwell&#xff0c;Sqoop&#xff0c;Logstash数据存储:MySQL&#xff0c;HDFS…

全网最最最详细的centos7如何设置静态ip

以下步骤假设你已经有了管理员权限&#xff08;或者可以使用sudo&#xff09;以及你的网络接口名称&#xff08;例如ens33&#xff09;。 步骤 1: 查找网络接口名称 打开终端。运行命令nmcli d来查看所有网络设备及其状态。找到你想配置的设备名称&#xff0c;比如ens33。 步…

结构指针的使用

结构指针的使用 指针类型变量&#xff1a; 指针类型&#xff0c;是变量类型的一种&#xff0c;它是专门用来存储变量的地址的。 例如 int *p; 表示p是一个指针变量&#xff0c;它用来存储某个整型变量的地址。 int a5; int *p&a; 这样&#xff0c;就将整型变量a的地…

Python语言元素之变量

程序是指令的集合&#xff0c;写程序就是用指令控制计算机做我们想让它做的事情。那么&#xff0c;为什么要用Python语言来写程序呢&#xff1f;因为Python语言简单优雅&#xff0c;相比C、C、Java这样的编程语言&#xff0c;Python对初学者更加友好。 一、一些计算机常识 在…

YOLOv9最新的改进项目来了!!

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;主力高效涨点&#xff01;&#xff01;&#xff01; YOLOv9作为最新的YOLO系列模型&#xff0c;对于做目标检测的同学是必不可少的。本专栏将针对2024年最新推出的YOLOv9检测模型&#xff0c;使用当前流…

RabbitMQ - 06 - Topic交换机

目录 控制台创建队列与交换机 编写消费者方法 编写生产者测试方法 结果 Topic交换机与Direct交换机基本一致 可参考 这篇帖子 http://t.csdnimg.cn/AuvoK topic交换机与Direct交换机的区别是 Topic交换机接收的消息RoutingKey必须是多个单词&#xff0c;以 . 分割 Topic交…

虚拟化

什么是虚拟化 虚拟化&#xff08;Virtualization&#xff09;是一种资源分配和管理技术&#xff0c;是将计算机的各种实体资源,比如CPU、内存、磁盘空间、网络适配器等&#xff0c;进行抽象转换后虚拟的设备,可以实现灵活地分割、组合为一个或多个计算机配置环境&#xff0c;并…

初探深度学习-手写字体识别

前言 手写数字的神经网络识别通常指的是通过训练有素的神经网络模型来识别和分类手写数字图像的任务。这种类型的任务是机器学习和计算机视觉领域的一个经典问题&#xff0c;经常作为入门级的图像识别问题来展示和测试各种机器学习算法的能力。在实际应用中&#xff0c;手写数…

寒假作业Day 09

寒假作业Day 09 一、选择题 因为一开始的for循环&#xff0c;k<2NN&#xff0c;所以复杂度为2N方&#xff0c;而后面的M10的while循环&#xff0c;则是10&#xff0c;复杂度为常数级&#xff0c;所以2N方10&#xff0c;近似于N方&#xff0c;即O(N^2) 这是一个计算阶乘的递…

excel批量数据导入时用poi将数据转化成指定实体工具类

1.实现目标 excel进行批量数据导入时&#xff0c;将批量数据转化成指定的实体集合用于数据操作&#xff0c;实现思路&#xff1a;使用注解将属性与表格中的标题进行同名绑定来赋值。 2.代码实现 2.1 目录截图如下 2.2 代码实现 package poi.constants;/*** description: 用…

一键部署Tesseract-OCR环境C++版本(Windows)

环境&#xff1a;Windows 10 工具&#xff1a;git vcpkg vscode cmake 库&#xff1a;Tesseract 一键部署Tesseract-OCR环境C版本&#xff08;Windows&#xff09; 分享这篇文章的原因很简单&#xff0c;就是为了让后续的朋友少走弯路。自己在搜索相关C版本的tesseract部署时…

【python量化】基于okex API开发的海龟策略

介绍 基于okex api开发的海龟策略&#xff0c;okex海龟策略python实现方式。该程序目前只支持单品种&#xff0c;比如设置ETH后&#xff0c;只对ETH进行做多做空。该程序运行需要两样东西&#xff1a;apikey 和 标的 运行该程序之前&#xff0c;用户需要到okex网站去申请apiK…

虚函数与纯虚函数有什么区别?

总的来说有两点区别&#xff1a; 1.虚函数的作用主要是矫正指针&#xff08;口语化的说法&#xff09; 2.虚函数不一定要重新定义&#xff0c;纯虚函数一定要定义&#xff08;口语化的说法&#xff09; 1&#xff09;. 虚函数的作用主要是矫正指针&#xff0c;使得基类的指针…

【Python数据结构与判断1/7】复杂的多向选择

目录 导入 举个栗子 代码优化 elif 栗子 执行顺序 情况一 情况二 情况三 if-elif-else特性 三种判断语句小结 if if-else if-elif-else 嵌套语句 if嵌套 栗子 执行顺序 相互嵌套 Tips Debug 总结 导入 在前面&#xff0c;我们学习了单向选择的if语句和多项…

Decontam去污染:一个尝试

为了程序运行的便利性&#xff0c;不想将Decontam放到windows的Rstudio里面运行&#xff0c;需要直接在Ubuntu中运行&#xff0c;并且为了在Decontam时进行其他操作&#xff0c;使用python去运行R 首先你需要有一个conda环境&#xff0c;安装了R&#xff0c;Decontam&#xff0…

day 49 动态规划 part 10● 121. 买卖股票的最佳时机 ● 122.买卖股票的最佳时机II

看了题解&#xff0c;第一种暴力&#xff0c;两个for循环。 class Solution { public:int maxProfit(vector<int>& prices) {int result 0;for (int i 0; i < prices.size(); i) {for (int j i 1; j < prices.size(); j){result max(result, prices[j] -…

使用scrapy爬取蜻蜓FM

创建框架和项目 ### 1. 创建虚拟环境 conda create -n spiderScrapy python3.9 ### 2. 安装scrapy pip install scrapy2.8.0 -i https://pypi.tuna.tsinghua.edu.cn/simple### 3. 生成一个框架并进入框架 scrapy startproject my_spider cd my_spider### 4. 生成项目 scrapy …