JAVA-13-IO流之字符流;设计模式讲解

来源:互联网 发布:linux locale命令 编辑:程序博客网 时间:2024/05/18 17:01

上一讲我们讲解了IO流中的字节流,本节我们继续讲解IO流中的字符流。
首先我们要先明白以下两点:
  ①字节流是通用的(我们用的最多的是基本字节流一次读写一个字节数组)。
  ②字符流一般只用于文本文档。
(四) 字符流及高效字符流
  字符输入流 Reader类(抽象类)
  字符输出流 Writer类(抽象类)
4.1 转换流 InputStreamReader、OutputStreamWriter
  学习字符流之前先学习转换流,InputStreamReader类(继承自Reader)和OutputStreamWriter类(继承自Writer),它们是字节流通向字符流的桥梁。
写入数据,把字节输出流转换为字符输出流(不指定码表)
  OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(“osw.txt”));
把字节输出流转换为字符输出流(指定码表)
  OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(“osw.txt”), “GBK”);
  OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(“osw.txt”), “UTF-8”);

读取数据, 把字节输入流转换为字符输入流(不指定码表)
  InputStreamReader isr = new InputStreamReader(new FileInputStream(“osw.txt”));
把字节输入流转换为字符输入流(指定码表)
  InputStreamReader isr = new InputStreamReader(new FileInputStream(“osw.txt”), “GBK”);
注意:我们一般创建字符输入或者输出流一般情况下使用系统默认的码表就可以,如果来来回回需要指定码表的话,就显得非常的麻烦。
4.2 FileReader 、FileWriter
  转换流实际上是创建转换流对象指向字节流对象,通过字节流间接操作文件;而且转换流创建的对象写起来比较复杂。为了简化这种操作,java就针对这两个转换的字符流提供其子类:
  FileReader(继承自InputStreamReader )
  FileWriter(继承自OutputStreamWriter)
它们的默认编码是采用系统编码。
  构造学习:
    FileWriter(File file)
    FileWriter(String fileName)
    FileReader(File file)
    FileReader(String fileName)
4.2.1 flush()和close()的区别?
  A:flush 刷新缓冲区,流对象可以继续
    FileWriter流必须写一次flush一次,但是FileReader流不需要
  B:close 先刷新缓冲区,再关闭流对象。流对象不可以继续使用。
    FileWriter对象一调用close方法,如果前面没有调用flush刷新,那么会默认flush,然后close;如果前面flush了就直接close。
4.2.2 字符输出流操作步骤:

  字符输出流操作步骤:    A:创建字符输出流对象    B:调用写数据方法(用法和字节输出流相似):      一次写一个字符  write(int c)       一次写一个字符数组write(char[] cbuf)      一次写一个字符数组的一部分write(char[] cbuf, int off,int len)      一次写一个字符串write(String str)      一次写一个字符串的一部分write(String str,int off,int len)    C:刷新缓冲区    D:释放资源

4.2.3 字符输入流操作步骤:

  字符输入流操作步骤:    A:创建字符输入流对象      FileReader fr = new FileReader("a.txt");    B:读取数据并显示在控制台      a:一次读取一个字符             int ch;             while ((ch = fr.read()) != -1) {             System.out.print((char) ch);             }         b:一次读取一个字符数组        char[] chs = new char[1024];             int len;             while ((len = fr.read(chs)) != -1) {                 System.out.print(new String(chs, 0, len));             }         C:释放资源        fr.close();

注意:字符流输入输出流复制的文件是有要求的,简单来说只要是记事本打开文件的内容我们能够看得懂,就可以用字符流来进行复制,否则不行。因为像复制MP3或者一些视频文件的时候,如果他的字节个数不是偶数的话,就会造成文件的缺损,因为一个字符等于两个字节
4.3 高效流:(特有方法readLine、newLine极为重要,是字符流中最常用的使用方式)
  首先,我们先考虑一个问题,如果要给文件中写入十个”helloworld”,每写一个换一行,那么每写一行我们就必须写入一个换行符“/r/n”,但是这样写有一定的弊端,因为windows系统下的换行符是“/r/n”,Linux是”\n”,Mac是”\r”,这样就会造成代码的通用性不强。
  那么我们该怎么操作才可以保证代码在任何平台都可以正常运行呢?java中为我们提供了两个类:BufferedReader字符缓冲输入流,BufferedWriter字符缓冲输出流,其中有一些方法可以完成我们的需求。
①BufferedReader:字符缓冲输入流
  构造:BufferedReader(Reader in)
  特殊方法:public String readLine():包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null
②BufferedWriter:字符缓冲输出流
  构造:BufferedWriter(Writer out)
  特殊方法:public void newLine():会根据系统来确定写入不同的换行符

package com.edu_08;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;public class Test {    public static void main(String[] args) throws IOException {        //封装数据源和目的地        BufferedReader br = new BufferedReader(new FileReader("InputStreamReaderDemo.java"));        BufferedWriter bw = new BufferedWriter(new FileWriter("copy.java"));        //读取一行写一行        String line;        while ((line = br.readLine())!=null) {            //System.out.println();            bw.write(line);            bw.newLine();            bw.flush();        }        //释放资源        bw.close();        br.close();    }}

4.4 字符流综合练习:
复制文本文件:
  基本字符流一次读写一个字符
  基本字符流一次读写一个字符数组
  高效字符流一次读写一个字符
  高效字符流一次读写一个字符数组

package com.edu_07;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;public class Test {    public static void main(String[] args) throws IOException {        method();//基本字符流一次读写一个字符        method2();//基本字符流一次读写一个字符数组        method3();//高效字符流一次读写一个字符        method4();//高效字符流一次读写一个字符数组    }    private static void method4() throws IOException {        //高效字符流一次读写一个字符数组        BufferedReader br = new BufferedReader(new FileReader("a.txt"));        BufferedWriter bw = new BufferedWriter(new FileWriter("j.txt"));        //一次读写一个字符数组        char[] chs = new char[1024];        int len;        while ((len = br.read(chs))!=-1) {            bw.write(chs, 0, len);            bw.flush();        }        //释放资源        bw.close();        br.close();    }    private static void method3() throws IOException {        //高效字符流一次读写一个字符        BufferedReader br = new BufferedReader(new FileReader("a.txt"));        BufferedWriter bw = new BufferedWriter(new FileWriter("j.txt"));        //一次读写一个字符        int ch;        while ((ch=br.read())!=-1) {            bw.write(ch);            bw.flush();        }        //关流        bw.close();        br.close();    }    private static void method2() throws IOException {        //基本字符流一次读写一个字符数组        FileReader fr = new FileReader("a.txt");        FileWriter fw = new FileWriter("j.txt");        //一次读写一个字节数组        char[] chs = new char[1024];        int len;        while ((len = fr.read(chs))!=-1) {            fw.write(chs, 0, len);            fw.flush();        }        //关流        fw.close();        fr.close();    }    private static void method() throws IOException {        //基本字符流一次读写一个字符        FileReader fr = new FileReader("a.txt");        FileWriter fw = new FileWriter("j.txt");        //一次读取一个字符,返回的是该字符对应的int值        int ch;        while ((ch=fr.read())!=-1) {            //System.out.println((char)ch);            fw.write(ch);            fw.flush();        }        //释放资源        fr.close();        fw.close();    }}

4.5 IO流综合练习
需求:键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低存入文本文件

package com.edu_09;//创建学生类public class Student {    private String name;    private int chinese;    private int math;    private int english;    public Student(String name, int chinese, int math, int english) {        super();        this.name = name;        this.chinese = chinese;        this.math = math;        this.english = english;    }    public Student() {        super();        // TODO Auto-generated constructor stub    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getChinese() {        return chinese;    }    public void setChinese(int chinese) {        this.chinese = chinese;    }    public int getMath() {        return math;    }    public void setMath(int math) {        this.math = math;    }    public int getEnglish() {        return english;    }    public void setEnglish(int english) {        this.english = english;    }    //获取总成绩的方法    public int getAllScore(){        return chinese+math+english;    }}
package com.edu_09;import java.io.BufferedWriter;import java.io.FileWriter;import java.io.IOException;import java.util.Comparator;import java.util.Scanner;import java.util.TreeSet;/** * 分析: * 1.创建学生类 * 2.键盘录入5个学生信息,并封装成学生对象,存储到TreeSet(使用比较器写一个排序算法) * 3.遍历集合,将信息存储到文本文件中(BufferedWriter) */public class StudentTest {    public static void main(String[] args) throws IOException {        //创建一个TreeSet集合,并写一个比较器        TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {            @Override            public int compare(Student s1, Student s2) {                int num = s2.getAllScore() - s1.getAllScore();                int num2 = num==0?s1.getName().compareTo(s2.getName()):num;                return num2;            }        });        //键盘录入5个学生信息        for (int i = 0; i < 5; i++) {            //创建键盘录入对象            Scanner sc = new Scanner(System.in);            //接受键盘录入数据            System.out.println("请输入你的姓名");            String name = sc.nextLine();            System.out.println("请输入你的语文成绩");            int chinese = sc.nextInt();            System.out.println("请输入你的数学成绩");            int math = sc.nextInt();            System.out.println("请输入你的英语成绩");            int english = sc.nextInt();            //封装成学生对象,存储集合            Student s = new Student(name, chinese, math, english);            ts.add(s);        }        System.out.println("数据录入完毕。。");        //遍历集合,将集合中的数据全取不出来之后写入文件中,每一个学生信息占一行        BufferedWriter bw = new BufferedWriter(new FileWriter("score.txt"));        for (Student s : ts) {            String info = s.getName()+"  "+s.getChinese()+"  "+s.getMath()+"  "+s.getEnglish()+"  "+s.getAllScore();            //将拼接成的字符串写入文件中            bw.write(info);            bw.newLine();            bw.flush();        }        //释放资源        bw.close();    }}

===============================================
设计模式讲解:
A:设计模式概述
  设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。
  使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性以及代码的结构更加清晰。
B:设计模式分类
  创建型模式(创建对象的): 单例模式、抽象工厂模式、建造者模式、工厂模式、原型模式。
  行为型模式(对象的功能): 适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
  结构型模式(对象的组成): 模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、
  解释器模式、状态模式、策略模式、职责链模式、访问者模式。
单例设计模式讲解(重点)
  A:单例设计思想
    保证类在内存中只有一个对象
  B:如何实现类在内存中只有一个对象呢?
    构造私有
    本身提供一个对象
    通过公共的方法让外界访问
C:单例模式有两种:饿汉式、懒汉式
饿汉式代码演练:

package com.edu_10;public class SingleInstanceDemo {    /**     * 饿汉式:当这个类一被加载,就在内存中创建了一个对象     *      * 1.保证内存中只有一个对象(构造私有)     * 2.在本类中创建一个该类的对象     * 3.创建一个公共的访问方式给外界获取该对象     */    private SingleInstanceDemo(){}    //静态的随着类的加载而加载    private static SingleInstanceDemo instance = new SingleInstanceDemo();    //给外界提供公共的访问方式,返回该对象    public static SingleInstanceDemo getInstance(){        return instance;    }}

测试:

package com.edu_10;public class SingleInstanceDemoTest {    public static void main(String[] args) {        SingleInstanceDemo instance = SingleInstanceDemo.getInstance();        SingleInstanceDemo instance2 = SingleInstanceDemo.getInstance();        System.out.println(instance==instance2);    }}//true,说明是一个对象

懒汉式代码演练:

package com.edu_10;public class SingleInstanceDemo2 {    /**     * 单例设计模式之懒汉式:     * 需要的时候才去创建对象,不需要的时候不创建     */    private SingleInstanceDemo2(){}    private static SingleInstanceDemo2 instance = null;    public static SingleInstanceDemo2 getInstance(){        if (instance==null) {            instance = new SingleInstanceDemo2();        }        return instance;    }   }

测试:

package com.edu_10;public class SingleInstanceDemo2Test {    public static void main(String[] args) {        SingleInstanceDemo2 instance = SingleInstanceDemo2.getInstance();        SingleInstanceDemo2 instance2 = SingleInstanceDemo2.getInstance();        System.out.println(instance==instance2);    }}//true,说明是一个对象

工厂设计模式
(1)简单工厂模式概述和使用
  A:简单工厂模式概述: 又叫静态工厂方法模式,它定义一个具体的工厂类负责创建一些类的实例
  B:优点: 使用静态工厂模式的优点是实现责任的分割,该模式的核心是工厂类,工厂类含有必要的选择逻辑,可以决定什么时候创建哪一个产品的实例,而客户端则免去直接创建产品的责任,而仅仅是消费产品。也就是说静态工厂模式在不改变客户端代码的情况可以动态的增加产品。明确了类的职责
  C:缺点:这个静态工厂类负责所有对象的创建,如果有新的对象增加,或者某些对象的创建方式不同,就需要不断的修改工厂类,不利于后期的维护
D:案例演示
①Animal 类

package com.edu_11;public abstract class Animal {    public abstract void eat();}

②Cat类继承Animal类

package com.edu_11;public class Cat extends Animal{    @Override    public void eat() {        System.out.println("猫吃鱼");    }}

③Dog类继承Animal类

package com.edu_11;public class Dog extends Animal{    @Override    public void eat() {        System.out.println("狗吃骨头");    }}

④AnimalFactory 类,专门用来生产对象

package com.edu_11;public class AnimalFactory {    //专门用来生产对象    public static Animal getAnimal(String type){        if ("dog".equals(type)) {            return new Dog();        }else if ("cat".equals(type)) {            return new Cat();        }        return null;    }}

⑤Test 测试类(main)

package com.edu_11;public class Test {    public static void main(String[] args) {//      Dog d = new Dog();//      Dog d2 = new Dog();//      d.eat();//      d2.eat();//      //      Cat c = new Cat();//      Cat c2 = new Cat();//      c.eat();//      c2.eat();        //如果说我们的类和对象比较多的话,这样每次去new对象的话,就显得不是非常的方便了        //此时我们需要专门创建一个工厂类,专门负责生产对象        Animal a = AnimalFactory.getAnimal("dog");        a.eat();//狗吃骨头        a = AnimalFactory.getAnimal("cat");        a.eat();//猫吃鱼    }}

(2)抽象工厂模式的概述和使用
  A:工厂方法模式概述
    工厂方法模式中抽象工厂类负责定义创建对象的接口,具体对象的创建工作由继承抽象工厂的具体类实现。
  B:优点
    客户端不需要在负责对象的创建,从而明确了各个类的职责,如果有新的对象增加,只需要增加一个具体的类和具体的工厂类即可,不影响已有的代码,后期维护容易,增强了系统的扩展性
  C:缺点: 需要额外的编写代码,增加了工作量
①Animal 类

package com.edu_12;public abstract class Animal {    public abstract void eat();}

②AnimalFactory 类,用于创建动物

package com.edu_12;public abstract class AnimalFactory {    //创建动物的功能    public abstract Animal getAnimal();}

③Cat类继承自Animal类

package com.edu_12;public class Cat extends Animal{    @Override    public void eat() {        System.out.println("猫吃鱼");    }}

④CatFactory类继承自AnimalFactory

package com.edu_12;public class CatFactory extends AnimalFactory{    @Override    public Animal getAnimal() {        // TODO Auto-generated method stub        return new Cat();    }}

⑤Dog 类继承自Animal

package com.edu_12;public class Dog extends Animal{    @Override    public void eat() {        System.out.println("狗吃骨头");    }}

⑥DogFactory 类继承自AnimalFactory

package com.edu_12;public class DogFactory extends AnimalFactory{    @Override    public Animal getAnimal() {        // TODO Auto-generated method stub        return new Dog();    }}

⑦新建Tiger 类继承自Animal

package com.edu_12;public class Tiger extends Animal{    @Override    public void eat() {        System.out.println("虎吃人");    }}

⑧新建TigerFactory 类继承自AnimalFactory

package com.edu_12;public class TigerFactory extends AnimalFactory{    @Override    public Animal getAnimal() {        // TODO Auto-generated method stub        return new Tiger();    }}

⑨Test 类(main)

package com.edu_12;public class Test {    public static void main(String[] args) {        //需要一个狗对象        AnimalFactory af = new DogFactory();        Animal a = af.getAnimal();        a.eat();        //需要一个猫对象        af = new CatFactory();        a = af.getAnimal();        a.eat();        //当突然有一天我需要一个老虎类的时候        //我只需要只需要新建Tiger类和TigerFactory类即可        //之前的代码不用做任何修改,后期维护容易,增强了系统的扩展性        af = new TigerFactory();        a = af.getAnimal();        a.eat();    }}
0 0
原创粉丝点击