黑马程序员全套Java教程_Java基础教程_IO流之特殊操作流(三十三)

4.1 标准输入输出流

  • System类中有两个静态的成员变量:
    (1)public static final InputStream in:标准输入流。通常该流对应于键盘输入或由主机环境或用户指定的另一个输入源;
    (2)public static final PrintStream out:标准输出流。通常该流对应于键盘输出或由主机环境或用户指定的另一个输出目标。
  • 自己实现键盘录入数据:
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

写起来太麻烦,Java就提供了一个类实现键盘录入:

        Scanner sc = new Scanner(System.in);
    public static void main(String[] args) throws IOException {
        1.标准输入流底层为字节流
        //InputStream is = System.in;
        2.字节流不方便中文的读取,所以通过转换流将其转换为字符流
        //InputStreamReader isr = new InputStreamReader(is);
        3.isr不能使用readLine()一次读一行数据,所以我们将其转换为字符缓冲流
        //BufferedReader br = new BufferedReader(isr);

        //1、2、3合并,将System.in包装
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        System.out.println("请输入一个字符串:");
        String line = br.readLine();
        System.out.println("你输入的字符串是:"+line);

        System.out.println("请输入一个整数:");
        int i = Integer.parseInt(br.readLine());
        System.out.println("你输入的整数是:"+i);

        //自己实现键盘录入数据太麻烦了,所以Java提供了一个类供我们使用
        Scanner sc = new Scanner(System.in);
    }
  • 输出的本质:是一个标准的输出流
    (1)PrintStream ps = System.out;
    (2)PrintStream类有的方法,System.out都可以使用。
    public static void main(String[] args) {
        PrintStream ps = System.out;
        
        //能够方便地打印各种数据值
        //ps.print("hello");
        //ps.print(100);
        //ps.println("hello");
        //ps.println(100);
        
        //System.out的本质是一个字节输出流
        System.out.println("hello");
        System.out.println(100);

        System.out.println();
        //System.out.print();
    }

4.2 打印流

  • 打印流分类:字节打印流PrintStream和字符打印流PrintWriter。
  • 打印流的特点:
    (1)只负责输出数据,不负责读取数据;
    (2)有自己的特殊方法。
  • 字节打印流:
    (1)PrintStream(String fileName):使用指定的文件名创建新的打印流;
    (2)使用继承父类的方法(write())写数据,查看的时候会转码;使用自己的特有方法写数据,查看的数据原样输出。
    public static void main(String[] args) throws FileNotFoundException {
        PrintStream ps = new PrintStream("mySpecialStream.txt");

        //使用字节输出流有的方法写数据
        ps.write(97);//写入了一个a

        //使用特有方法写数据
        //ps.print(97);
        //ps.println();
        //ps.print(98);
        ps.println(97);//写入了97
        ps.println(98);

        ps.close();
    }
  • 字符打印流PrintWriter的两个构造方法:
方法名说明
PrintWriter(String fileName)使用会的那个的文件名创建一个新的PrintWriter,而不需要自动执行刷新
PrintWriter(Writer out, boolean autoFlush)创建一个新的PrintWriter。out为字符字符输出流;autoFlush为一个布尔值,如果为真,则println、printf或format方法将刷新输出缓冲区
    public static void main(String[] args) throws IOException {
        //PrintWriter pw = new PrintWriter("mySpecialStream.txt");
        //
        pw.write("hello");
        pw.write("\r\n");
        pw.flush();
        pw.write("world");
        pw.write("\r\n");
        pw.flush();
        //
        //pw.println("hello");
        //pw.flush();
        //pw.println("world");
        //pw.flush();

        PrintWriter pw2 = new PrintWriter(new FileWriter("mySpecialStream.txt"),true);
        pw2.println("hello");
        pw2.println("world");
        
        pw2.close();
    }

案例:复制Java文件(打印流改进版)

  • 把模块目录下的PrintStreamDemo.java复制到模块目录下的Copy.java。
  • 思路:
    (1)根据数据源创建字符输入流对象;
    (2)根据目的地创建字符输出流对象;
    (3)读写数据,复制文件;
    (4)释放资源。
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader("src\\itheima2\\PrintStreamDemo.java"));
        PrintWriter ps = new PrintWriter(new FileOutputStream("Copy.java"),true);

        String line;
        while ((line=br.readLine()) != null){
            //字符缓冲输出流要3步,而用打印流只要1步
            ps.println(line);
        }

        br.close();
        ps.close();
    }

4.3 对象序列化流

  • 对象序列化:就是将对象保存到磁盘中,或者在网络中传输对象。这种机制就是使用一个字节序列表示一个对象,该字节序列包括对象的类型、对象的数据和对象中存储的属性等信息。字节序列写到文件之后,相当于文件中持久保存了一个对象的信息。反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。要实现序列化和反序列化就要使用对象序列化流对象反序列化流
  • 对象序列化流ObjectOutputStream:
    (1)对象序列化流将Java对象的原始数据类型和图形写入OutputStream,可以使用ObjectInputStream读取(重构)对象。它通过使用流的文件来实现对象的持久存储。如果是网络套接字流,则可以在另一个主机上或另一个进程中重构对象。
    (2)构造方法:ObjectOutputStream(OutputStream out),创建一个将数据写入指定OutputStream的ObjectOutputStream。
    (3)序列化对象的方法:void writeObject(Object obj):将指定的对象写入ObjectOutputStream。
    (4)注意:一个对象想要被序列化,该对象所属的类必须实现Serializable接口,Serializable是一个标记接口,实现该接口,不需要重写任何方法。
public class Student implements Serializable {
    private String name;
    private int age;

    public Student() {
    }

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    public static void main(String[] args) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Copy.java"));

        Student s = new Student("liubei",11);

        oos.writeObject(s);//NotSerializableException不可序列化异常,a.Serializable序列化的

        oos.close();
    }
  • 对象反序列化流ObjectInputStream:
    (1)ObjectInputStream反序列化先前使用ObjectOutputStream编写的原始数据和对象;
    (2)ObjectInputStream(InputStream in):创建一个从指定InputStream读取数据的ObjectInputStream;
    (3)反序列化对象的方法:Object readObject(),从ObjectInputStream读取一个对象。
public class ObjectInputStreamDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Copy.java"));

        Object obj = ois.readObject();

        System.out.println((Student)obj);

        ois.close();
    }
}
  • 用对象序列化程序序列化一个对象后,加入我们修改了对象所属的类的文件,读数据会不会出问题呢?如果出问题了,如何解决呢?
    会出问题,抛出InvalidClassException异常。解决方法是给对象所属的类加一个serialVersionUID,如private static final long serialVersionUID = 42L。
  • 如果一个对象中的某个成员变量的值不想被序列化,又如何实现呢?
    给该成员变量加transient关键字修饰,该关键字标记的成员变量不参与序列化过程。如private transient int age。
public class Student implements Serializable {
    private static final long serialVersionUID = 42L;
    private String name;
    //private int age;
    private transient int age;

    public Student() {
    }

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

    //@Override
    //public String toString() {
    //    return "Student{" +
    //            "name='" + name + '\'' +
    //            ", age=" + age +
    //            '}';
    //}
    ................
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        /*	修改了类所属对象的文件,报错:java.io.InvalidClassException:
                                itheima3.Student; local class incompatible:
                                stream classdesc serialVersionUID = 8774687461010984637
                                local class serialVersionUID = 3150362556242052030
			InvalidClassException当序列化时检测到类中的以下问题之一时抛出:
			1、类的串行版本与从流中读取的类描述符的类型不匹配;
			2、该类包含位置的数据类型;
			3、该类没有可访问的无参构造函数。
		*/
        write();
        //read();
    }

    //反序列化
    private static void write() throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Copy.java"));
        Object obj = ois.readObject();
        Student s = (Student)obj;
        System.out.println("Student{" +
                "name='" + s.getName() + '\'' +
                ", age=" + s.getAge() +
                '}');
        ois.close();
    }

    //序列化
    private static void read() throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Copy.java"));
        Student s = new Student("liubei",11);
        oos.writeObject(s);//NotSerializableException不可序列化异常,a.Serializable序列化的
        oos.close();
    }

面试题:下面哪个流输入面向字符的输入流?

  • (A)InputStreamReader (B)BufferedWriter (C)FileInputStream (D)ObjectInputStream
  • BufferedWriter为字符缓冲输出流; FileInputStream为字节输入流;ObjectInputStream为对象反序列化流。

4.4 Properties

  • Properties概述:是一个Map体系的集合,可以保存到流中或者从流中加载。
  • Propertie作为Map集合的使用:
    public static void main(String[] args) {
        //Properties<String,String> prop = new Properties<String,String>();//错误
        Properties prop = new Properties();

        prop.put("liubei", 22);
        prop.put("guanyu", 21);
        prop.put("zhangfei", 11);

        Set<Object> keySet = prop.keySet();
        for (Object key : keySet) {
            Object value = prop.get(key);
            System.out.println(key + "," + value);
        }
    }
  • Properties作为集合的特有方法:
方法名说明
Object setProperty(String key, String value)设置集合的键和值,都是String类型,底层调用Hashtable方法put
String getProperty(String key)使用此属性列表中指定的键搜索属性对应的值
Set stringPropertyNames()从该属性列表中返回一个不可修改的键集(键的集合),其中键及其对应的值是字符串
    public static void main(String[] args) {
        Properties prop = new Properties();

        /*
            public synchronized Object setProperty(String key, String value) {
                return put(key, value);
            }
            Object put(Object key, Object value) {
                return map.put(key, value);
            }
         */
        prop.setProperty("001","liubei");
        prop.setProperty("002","guanyu");
        prop.setProperty("003","zhangfei");
        System.out.println(prop);//{003=zhangfei, 002=guanyu, 001=liubei}

        System.out.println(prop.getProperty("001"));//liubei
        System.out.println(prop.getProperty("002"));//guanyu
        System.out.println(prop.getProperty("003"));

        Set<String> names = prop.stringPropertyNames();
        for (String key : names){
            System.out.print(key + ",");
            System.out.print(prop.getProperty(key) + " ");//003,zhangfei 002,guanyu 001,liubei
        }
    }
  • Properties和IO流结合的方法:
方法名说明
void load(InpuStream inStream)从输入字节流读取属性列表(键和元素对即键值对)
void load(Reader reader)从输入字符流读取属性列表(键和元素对)
void store(OutpuStream out, String comments)将此属性列表(键和元素对)写入此Properties表中,以适合于使用load(InputStream)方法的格式写入输出字节流
void store(Writer writer, String comments)……适合于使用load(Reader)方法的格式写入输出字符流
    public static void main(String[] args) throws IOException {
        myStore();
        myLoad();
    }

    private static void myLoad() throws IOException {
        Properties prop = new Properties();

        FileReader fr = new FileReader("Copy.java");
        prop.load(fr);
        fr.close();

        System.out.println(prop);//{003=zhanfei, 002=guanyu, 001=liubei}
    }

    private static void myStore() throws IOException {
        Properties prop = new Properties();
        prop.setProperty("001","liubei");
        prop.setProperty("002","guanyu");
        prop.setProperty("003","zhanfe");

        FileWriter fw = new FileWriter("Copy.java");
        prop.store(fw,null);//描述信息可以不写

        fw.close();
    }

案例:游戏次数

  • 需求:请写程序实现猜数字小游戏只能试玩3次,如果还想玩,提示:游戏试玩已结束,想玩请充值(www.itcast.cn)。
  • 思路:
    (1)写一个游戏类,里面有一个猜数字的小游戏;
    (2)写一个测试类,测试类中有main(),main()方法中按照下面步骤完成:
    A:从game.txt文件中读取数据到Properties集合,用load()实现。game.txt文件已存在且里面有一个数据值count=0;
    B:通过Properties集合获取到玩游戏的次数;
    C:判断次数是否到达了三次。如果到了,给出“游戏试玩已结束,想玩请充值(www.itcast.cn)”的提示;如果没到。玩游戏,count++,重新写回文件,用Properties的store()实现。
public class GuessNumber {
    private GuessNumber(){};

    public static void start() {
        Random r = new Random();
        int number = r.nextInt(10) + 1;

        while (true){
            Scanner sc = new Scanner(System.in);

            System.out.println("请输入您猜的数字:");
            int guessNumber = sc.nextInt();

            if (guessNumber>number){
                System.out.println("您猜的数字大了");
            }else if (guessNumber < number){
                System.out.println("您猜的数字小了");
            }else {
                System.out.println("您猜对了!");
                break;
            }
        }
    }
}
    public static void main(String[] args) throws IOException {
        int count = 0;
        while (true) {
            Properties prop = new Properties();
            FileReader fr = new FileReader("game.txt");
            prop.load(fr);
            fr.close();
            count = Integer.parseInt(prop.getProperty("count"));
            if (count>=3){
                System.out.println("游戏试玩已结束,请充值!");
                System.out.println("(www.itcast.cn)");
                break;
            }else {
                GuessNumber.start();
                count++;
                prop.put("count",String.valueOf(count));
                FileWriter fw = new FileWriter("game.txt");
                prop.store(fw,null);
                fw.close();
            }
        }
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值