美文网首页
3/23day17_缓冲流_转换流_序列化流_打印流_装饰设计模

3/23day17_缓冲流_转换流_序列化流_打印流_装饰设计模

作者: 蹦蹦跶跶的起床啊 | 来源:发表于2020-03-23 15:37 被阅读0次

    复习

    1.字符流
        FileWriter FileReader
    2.ResourceBundle
    3.Properties
        a.都可以读取Properties配置文件
        区别:
            a.ResourceBundle是静态方法getBundle,Properties成员方法load
            b.ResourceBundle一般读取src根目录下,Properties一般读取项目根目录下
            c.ResourceBundle读取时只需要写文件名(不带后缀), Properties读取时文件名要写全名
                
    4.异常处理    
        JDK1.7之前
            try{
                
            }catch(Exception e){
                
            }finally{
                xxx.close();
            }
        JDK1.7以及之后
            try(FileReader fr = new FileReader("1.txt")){
                
            }catch(Exception e){
                
            }
        
    

    今日内容

    • 缓冲流(高效流, 比普通流性能更高)
    • 转换流(编码相关的流, 指定编码)'
    • 序列化流(操作对象)
    • 打印流(System.out.println())
    • 设计模式(装饰设计模式, 4个步骤)
    • common-io 工具包(简化io代码)

    缓冲流

    缓冲流的介绍

    • 介绍

      缓冲流,也叫高效流,是对4个基本的 FileXxx 流的增强(性能增强, 方法基本一样),所以也是4个流

    • 缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。

    缓冲流的分类

    • 按照数据类型分类:

      缓冲字节输入流: BufferedInputStream ---> 对普通的字节输入流``InputStream`增强

      缓冲字节输出流: BufferedOutputStream ---> 对普通的字节输出流OutputStream增强

      缓冲字符输入流: BufferedReader ---> 对普通的字符输入流Reader增强

      缓冲字符输出流: BufferedWriter ---> 对普通的字符输出流Writer增强

    字节缓冲流的介绍和使用

    • 字节缓冲流的构造

      public BufferedInputStream(InputStream in):创建一个 新的缓冲输入流。
      public BufferedOutputStream(OutputStream out): 创建一个新的缓冲输出流。

    • 字节缓冲流的使用代码

      (使用一次读取一个字节数组的方式,配合字节缓冲流使用速度更快)

          public static void copy01() throws Exception{
              BufferedInputStream bis = new BufferedInputStream(new FileInputStream("1.txt"));
              BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("2.txt"));
              long start = System.currentTimeMillis();
              int b = 0;
              while ((b = bis.read()) != -1) {
                  bos.write(b);
              }
              long end = System.currentTimeMillis();
              bis.close();
              bos.close();
              System.out.println(end-start);
          }
      

    字符缓冲流的介绍和使用

    • 字符缓冲流的构造

      public BufferedReader(Reader in):创建一个 新的缓冲输入流。
      public BufferedWriter(Writer out): 创建一个新的缓冲输出流。

    • 字符缓冲流的特有方法

      BufferedReadpublic String readLine() : 读一行文字(只要没到换行)。(读不到会返回null)
      BufferedWriterpublic void newLine() : 写一行行分隔符(换行符),由系统属性定义符号(具有跨平台性)。

      • BufferedRead的一次读取一行使用

        public static void bwread() throws IOException{
            BufferedReader br = new BufferedReader(new FileReader("2.txt"));
            System.out.println(br.readLine());
            //===========一次读取一行的标准写法==========
            String line="";
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
            br.close();
        }
        

        缓冲流练习

    public static void main(String[] args) throws IOException {
        ArrayList<String> list = new ArrayList<>();
        BufferedReader br = new BufferedReader(new FileReader("1.txt"));
        String line ="";
        while ((line = br.readLine()) != null) {
            list.add(line);
        }
        br.close();
        /* Collections.sort(list, new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                    return o1.charAt(0)-o1.charAt(0);
                }
            });*/
        Collections.sort(list,((o1, o2) -> o1.charAt(0)-o2.charAt(0)));
        /*for (String s : list) {
                System.out.println(s);
            }*/
        BufferedWriter bw = new BufferedWriter(new FileWriter("2"));
        for (String s : list) {
            bw.write(s);
            bw.newLine();
        }
        bw.close();
    }
    

    转换流

    编码和解码

    • 编码: 把字符按照某种规则,将字符转到字节(二进制)存储到计算机中,称为编码 。

    • 解码: 将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码 。

    字符集

    字符集 Charset :也叫编码表。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。

    字符编码

    字符编码 Character Encoding : 就是一套自然语言的字符与二进制数之间的对应规则。

    常见的字符集和字符编码

    ASCII 字符集 --> ASCII 编码 , 规定了ASCII字符集中所有的字符都占1个字节(0-127)用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显
    示字符(英文大小写字符、阿拉伯数字和西文符号)。

    GBK字符集 ---> GBK编码, 规定所有的中文字符都占2个字节(这2个字节都是负数).是为了显示中文而设计的一套字符集。

    Unicode字符集 ---> UTF-8编码, 规定所有中文字符都占3个字节,Unicode编码系统为表达任意语言的任意字符而设计,是业界的一种标准,也称为统一码、标准万国码。

    ISO-8859-1字符集 ---> 用于显示欧洲使用的语言

    编码引出的问题

    IDEA默认使用UTF-8编码, windows默认使用GBK编码

    public class ReaderDemo {
        public static void main(String[] args) throws IOException {
            FileReader fileReader = new FileReader("E:\\File_GBK.txt");
            int read;
            while ((read = fileReader.read()) != -1) {
                System.out.print((char)read);
            }
            fileReader.close();
        }
    }
    输出结果:
    ���
    

    使用转换流InputStreamReader类解决读取中文的问题

    转换流 java.io.InputStreamReader ,是Reader的子类,是从字节流到字符流的桥梁。它读取字节,并使用指定的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集。

    • 构造方法

      InputStreamReader(InputStream in) : 创建一个使用默认字符集的字符流。(使用IDEA默认编码)
      InputStreamReader(InputStream in, String charsetName): 创建一个指定字符集的字符流。(第二个参数为指定使用何种编码读取文件)

    使用转换流OutputStreamReader类写不同编码的中文

    转换流 java.io.OutputStreamWriter ,是Writer的子类,是从字符流到字节流的桥梁。使用指定的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集。

    • 构造方法

      OutputStreamWriter(OutputStream in): 创建一个使用默认字符集的字符流。
      OutputStreamWriter(OutputStream in, String charsetName) : 创建一个指定字符集的字符流。

    • 按指定编码输出

      public static void main(String[] args) throws Exception {
          OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("1.txt"), "UTF-8");
          osw.write("你好");
          osw.close();
      }
      

    转换流的理解

    转换流代码案例

    public static void main(String[] args) throws Exception{
        InputStreamReader isr = new InputStreamReader(new FileInputStream("GBK.txt"), "GBK");
        OutputStreamWriter ops = new OutputStreamWriter(new FileOutputStream("UTF-8.TXT"), "UTF-8");
        int ch=0 ;
        while ((ch = isr.read()) != -1) {
            ops.write((char)ch);
        }
        isr.close();
        ops.close();
    }
    

    序列化

    序列化流概述

    • 序列化流: 写出对象的流

      ObjectOutputStream(java.io.ObjectOutputStream 类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。)

    • 反序列化流: 读取对象的流

      ObjectInputStream(ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。)

    ObjectOutputStream类的介绍和使用

    • 构造方法

      public ObjectOutputStream(OutputStream out): 创建一个指定OutputStream的ObjectOutputStream。

    • 序列化操作的前提

      想要序列化, 必须将需要序列化的对象类实现Serializable(可序列化)接口

      Serializable接口没有需要重写的方法, 这种接口被称为标记接口

    • 序列化操作代码演示

          public static void main(String[] args) throws Exception{
              ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("dog.txt"));
              oos.writeObject(new Dog(20,"小狗狗"));
              oos.close();
          }
      

      写出的dog.txt文件中是字节文件.

    ObjectInputStream类的介绍和使用

    • 构造方法

      public ObjectInputStream(InputStream in) : 创建一个指定InputStream的ObjectInputStream。

    • 反序列化操作代码演示

      public static void main(String[] args) throws Exception{
          ObjectInputStream ois = new ObjectInputStream(new FileInputStream("dog.txt"));
          Object o = ois.readObject();
          System.out.println(o);
          ois.close();
      }
      

    反序列化可能会出现的异常

    • 对于JVM可以反序列化对象,它必须是能够找到class文件的类。如果找不到该类的class文件,则抛出一个ClassNotFoundException 异常。

      原因: 找不到序列化时的对象类

    • 当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操作也会失败,抛出一个 InvalidClassException异常。

      原因: 修改了序列化的对象类的内容,根据版本号识别

    • Serializable 接口给需要序列化的类,提供了一个序列版本号。 serialVersionUID 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。(允许程序员自己管理版本号代码如下)

      public class Employee implements java.io.Serializable {
           // 加入序列版本号
           private static final long serialVersionUID = 1L;
           public String name;
           public String address;
           // 添加新的属性 ,重新编译, 可以反序列化,该属性赋为默认值.
           public int eid; 
       
           public void addressCheck() {
               System.out.println("Address  check : " + name + " -- " + address);
           }
      }
      

    序列化多个对象

    • 注意: 序列化流一个文件只适合序列化一个对象(如果一个文件序列化多个对象, 会缺少标记)

    • 操作步骤:

      1. 把序列化的多个对象,保存到一个集合对象(集合已经实现了Serializable接口)
      2. 把这个集合作为对象,序列化到文件中(其实就是将集合容器作为对象序列化到文件中)
    • 序列化多个对象代码演示:

      public class TestDemo {
          public static void main(String[] args) throws Exception {
              write();
              read();
          }
          public static void write() throws IOException {
              ArrayList<Dog> dogs = new ArrayList<>();
              dogs.add(new Dog(23, "dahua"));
              dogs.add(new Dog(11, "erhua"));
              dogs.add(new Dog(55, "sanhua"));
      
              ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("dogs.txt"));
              oos.writeObject(dogs);
              oos.close();
          }
          public static void read() throws Exception {
              ObjectInputStream ois = new ObjectInputStream(new FileInputStream("dogs.txt"));
              Object o  = ois.readObject();
              //反序列化文件, 返回值是Object对象, 需要强转成集合(泛型用父类多态接收)
              for (Object dog : (ArrayList<Object>)o) {
                  System.out.println(dog);
              }
              ois.close();
          }
      }
      
      

    打印流(PrintStream)

    打印流的介绍

    System.out.println()在控制台打印输出,是调用print 方法和 println 方法完成的,这两个方法都来自于java.io.PrintStream 类(成为打印流),该类能够方便地打印各种数据类型的值(打印流中重写了各种数据类型的printprintlin方法),是一种便捷的输出方式。

    打印流的用法

    • 构造方法

      public PrintStream(String fileName): 使用指定的文件名创建一个新的打印流。

      public PrintStream(File file): 直接指定file对象

      public PrintStream(OutputStream out): 输出流绑定的哪个对象, 就打印到哪个对象中

    • 成员方法

      public void print(各种数据类型);

      public void println(各种数据类型);

    • 打印流代码演示

      public static void main(String[] args) throws Exception{
          PrintStream ps1 = new PrintStream("p.txt");
          PrintStream ps2 = new PrintStream(new File("p1.txt"));
          PrintStream ps3 = new PrintStream(new FileOutputStream("p2.txt"));
          ps1.print("随便写各种类型数据");
      }
      
    • 修改系统打印流的流向

      public static void main(String[] args)  throws Exception{
          PrintStream ps = new PrintStream("p.txt");
          ps.print("更改打印");
          System.out.println("JAVA");
          //相当于修改了System静态变量out的值
          System.setOut(ps);
          System.out.println();
          System.out.println("java更改");
      }
      

    装饰设计模式

    设计模式是指, 前辈们为了解决一系列问题设计的方案

    在我们今天所学的缓冲流中涉及到java的一种设计模式,叫做装饰模式.

    装饰设计模式概述(作用)

    指在不改变原类, 不适用继承的基础上, 动态地扩展一个对象的功能.

    装饰设计模式的4个基本步骤

    • 装饰类(需要装饰的新类)和被装饰类(原类)必须实现相同的接口(可以将原类中的成员方法抽出来, 放在接口中)
    • 在装饰类中必须传入被装饰类的引用(就是在新类中定义装饰类的成员变量对象)
    • 在装饰类中对需要扩展的方法进行扩展
    • 在装饰类中对不需要扩展的方法调用被装饰类中的同名方法

    装饰设计模式代码演示

    1. 先提供方法接口

      public interface Star {
          public void sing();
          public void dance();
      }
      
    2. 让原类去实现接口

      public class LiuDeHua implements Star {
          @Override
          public void sing() {
              System.out.println("刘德华在唱忘情水...");
          }
          @Override
          public void dance() {
              System.out.println("刘德华在跳街舞...");
          }
      }
      
    3. 写装饰类,在装饰类中扩展

      /*
          装饰模式遵循原则:
              装饰类和被装饰类必须实现相同的接口
              在装饰类中必须传入被装饰类的引用
              在装饰类中对需要扩展的方法进行扩展
              在装饰类中对不需要扩展的方法调用被装饰类中的同名方法
      */
      public class LiuDeHuaWarpper implements Star {
          // 存放被装饰类的引用
          private LiuDeHua liuDeHua;
          // 通过构造器传入被装饰类对象
          public LiuDeHuaWarpper(LiuDeHua liuDeHua){
              this.liuDeHua = liuDeHua;
          }
          @Override
          public void sing() {
              // 对需要扩展的方法进行扩展增强
              System.out.println("刘德华在鸟巢的舞台上演唱忘情水.");
          }
          @Override
          public void dance() {
              // 不需要增强的方法调用被装饰类中的同名方法
              liuDeHua.dance();
          }
      }
      

    commons-io工具包

    commons-io工具包概述

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

    功能描述
    org.apache.commons.io 有关Streams、Readers、Writers、Files的工具类
    org.apache.commons.io.input 输入流相关的实现类,包含Reader和InputStream
    org.apache.commons.io.output 输出流相关的实现类,包含Writer和OutputStream
    org.apache.commons.io.serialization 序列化相关的类

    commons-io工具包 使用步骤

    步骤:

    1. 下载commons-io相关jar包;http://commons.apache.org/proper/commons-io/
    2. 把commons-io-2.6.jar包复制到指定的Module的lib目录中(必须在指定的Module的lib目录下, lib目录和src目录为同级目录)
    3. 将commons-io-2.6.jar加入到classpath中(IDEA中右键该工具包选择Add as Libary表示添加到本模块中作为工具库)

    commons-io工具包常用API

    • commons-io提供了一个工具类 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 static void main(String[] args) throws Exception {
           // 文件路径需要修改,改成自己文件的路径
           File file = new File("src/test.txt");
           FileInputStream is = new FileInputStream(file);
           // 文件路径需要修改
           File file1 = new File("src/test1.txt");
           FileOutputStream os = new FileOutputStream(file1);
           // 文件复制
           IOUtils.copy(is, os);
       }
      
    • commons-io还提供了一个工具类org.apache.commons.io.FileUtils,封装了一些对文件操作的方法:

      1. public static void copyFileToDirectory(final File srcFile, final File destFile) //复制文件到另外一个目录
        下。
      2. public static void copyDirectoryToDirectory( file1 , file2 );//复制file1目录到file2位置。

      代码演示

      public static void main(String[] args) throws IOException {
              //1.将d:\\视频.itcast文件复制到e:\\下
              FileUtils.copyFileToDirectory(new File("d:\\视频.itcast"), new File("e:\\"));
              //2.将"d:\\多级目录"复制到"e:\\"下。
              FileUtils.copyDirectoryToDirectory(new File("d:\\多级目录"), new File("e:\\"));
          }
      

    今日小结

    1.缓冲流【重点】
    字节缓冲流(BufferedOutputStream和BufferedInputStream),没有特有方法,性能比普通流更高

    字符缓冲流(BufferedWriter和BufferedReader),有特有方法,性能比普通流更高
      BufferedWriter: 
          public void newLine();
      BufferedReader:
          public String readLine();
    

    2.转换流【重点】
    转换输出流: 可以指定编码写文件
    OutputStreamWriter
    public OutputStreamWriter(OutputStream out,String 指定的编码);
    转换输入流: 可以指定编码读文件
    InputStreamReader
    public InputStreamReader(InputStream in,String 指定的编码);

    3.序列化流【理解】
    序列化流: 写对象
    ObjectOutputStream
    public void writeObject(对象);//该对象的类必须实现java.io.Serializable接口
    反序列化流: 读对象
    ObjectInputStream
    public Object readObject();
    4.打印流【理解】
    PrintStream ps = new PrintStream(String path/File file/OutputStream out);
    方法:
    print(各种数据类型);
    println(各种数据类型);

    5.装饰设计模式【理解】
    步骤:
    a.被装饰类和装饰类实现同一个接口
    b.装饰类内部必须含有被装饰类的引用
    c.在装饰类中对需要装饰的方法进行装饰
    d.在装饰类中对不需要装饰的方法调用原对象的方法

    6.commons-io【重点】
    IOUtils 复制文件(2G以上和2G以下)
    FileUtils 复制文件和复制文件夹

    相关文章

      网友评论

          本文标题:3/23day17_缓冲流_转换流_序列化流_打印流_装饰设计模

          本文链接:https://www.haomeiwen.com/subject/sbuwyhtx.html