3/23day17_缓冲流_转换流_序列化流_打印流_装饰设计模式_common-io 工具包

复习

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 复制文件和复制文件夹

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容