IO流——特殊操作类 & Properties集合

本文详细介绍了Java中的IO流,包括标准输入输出流的使用,字节打印流和字符打印流的构造与方法,以及如何进行对象的序列化和反序列化。此外,还讲解了Properties集合的特性、方法以及结合IO流的操作。文章通过实例代码展示了如何在实际操作中运用这些流技术。
摘要由CSDN通过智能技术生成

特殊操作流

1. 标准输入流 & 标准输出流

1.1 概述

  • System类中有两个静态的成员变量
    • public static final InputStream in:标准输入流。通常该流对应于键盘输入或由主机环境或用户指定的 另一个输入源
    • public static final PrintStream out:标准输出流。通常该流对应于显示输出或由主机环境或用户指定的 另一个输出目标

1.2 示例

  • 标准输入流
//自己实现键盘录入数据过于麻烦,所以Java体统了一个类供我们使用
Scanner sc = new Scanner(System.in);
  • 标准输出流

    //System.out的本质是一个字节输出流
    System.out.print(); //不换行
    System.out.println(); //换行
    

2. 字节打印流 & 字符打印流

2.1 概述

  • PrintStream:字节打印流
  • PrintWriter:字符打印流
  • 使用继承父类的方法写数据,查看的时候会转码;使用自己的特有方法写数据,查看的数据原样输出
  • 可以改变输出语句的目的地
    • public static void setOut(PrintStream out):重新分配“标准”输出流

2.2 特点

  • 只负责输出数据,不负责读取数据
  • 永远不会抛出IOException
  • 有自己特有的方法

2.3 构造方法

2.3.1 字节打印流
方法名说明
PrintStream(String fileName)使用指定的文件名创建新的打印流
2.3.2 字符打印流
方法名说明
PrintWriter(String fileName)使用指定的文件名创建一个新的PrintWriter,不会自动执行刷新
PrintWriter(Writer out, boolean autoFlush)创建一个新的PrintWriter out:字符输出流 autoFlush: 一个布尔值,如果 为真,则println 、print 或format方法将刷新输出缓冲区

2.4 代码示例

2.4.1 字节打印流
import java.io.IOException;
import java.io.PrintStream;
//字节打印流
public class Demo01 {
    public static void main(String[] args) throws IOException {
        PrintStream ps = new PrintStream("iodemo\\demo.txt");
        //字节输出流的方法 写数据
        ps.write(97); //写入的是a
        //字节打印流 特有方法写数据
        ps.print(97); // 写的是多少 写入的就是多少
        ps.println(98);//换行
        ps.print(99);
        //释放资源
        ps.close();
    }
}
2.4.2 字符打印流
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class Demo02 {
    public static void main(String[] args) throws IOException {
/*        //第一种构造方法
        PrintWriter pw = new PrintWriter("iodemo\\demo.txt");
        pw.write("hello");
        pw.write("\r\n");
        pw.flush();
        //println 自动换行
        pw.println("world");
        pw.flush();*/

        //第二种构造方法    加一个参数必须为true 这种构造方法能实现自动刷新
        PrintWriter pw = new PrintWriter(new FileWriter("iodemo\\demo.txt"),true);
        pw.println("hello");
        /* 这一步相当于 第一种构造方法中
        pw.write("hello");
        pw.write("\r\n");
        pw.flush();
         */
        pw.println("world");
        pw.close();
    }
}

2.5 复制Java文件(打印流改进版)

import java.io.*;
//复制Java文件 (打印流改进)
/*
1.根据数据源创建字符缓冲输入流对象
2.根据目的地创建字符打印流对象
3.读写数据,复制文件
4.释放资源
 */
public class Test01 {
    public static void main(String[] args) throws IOException {
        //由于打印流只能写数据 不能读数据 所以读数据还是使用 字符缓冲输入流来进行
        BufferedReader br = new BufferedReader(new FileReader("iodemo\\src\\com\\wang\\test\\Test01.java"));
        //创建打印流对象
        PrintWriter pw = new PrintWriter(new FileWriter("iodemo\\Test.java"),true);
        //读数据仍用 字符缓冲输入流的方法
        String line;
        while ((line = br.readLine()) != null){
            //写数据采用打印字符流
            pw.println(line);
            /*
            bw.write(String);
            bw.nerLine();
            bw.flush();
             */
        }
        //释放资源
        br.close();
        pw.close();
    }
}

3. 对象序列化流 & 对象反序列化流

3.1 概述

  • 对象序列化:就是将对象保存到磁盘中,或者在网络中传输对象

  • 这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的类型、对象的数据和对象中存储的属性等信息字节序列写到文件之后,相当于文件中持久保存了一个对象的信息

  • 反之,该字节序列还可以从文件中读取回来,重构对象,对它进行 反序列化

  • 要实现序列化和反序列化就要使用对象序列化流和对象反序列化流

    • ObjectOutputStream:对象序列化流
    • ObjectInputStream:对象反序列化流

3.2 对象序列化流

3.2.1 概述
  • 将Java对象的原始数据类型和图形写入OutputStream。 可以使用ObjectInputStream读取(重构)对象。可以通过使用流的文件来实现对象的持久存储。 如果流是网络套接字流,则可以在另一个主机上或另一个进程中重构对象
3.2.2 构造方法 & 方法
构造方法说明
ObjectOutputStream(OutputStream out)创建一个写入指定的OutputStream的 ObjectOutputStream
方法名说明
void writeObject(Object obj)将指定的对象写入ObjectOutputStream
3.2.3 代码示例
  • 测试类
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class Demo03 {
    public static void main(String[] args) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("iodemo\\demo.txt"));

        Student03 s1 = new Student03("张三", 18);

        oos.writeObject(s1);

        oos.close();
    }
    //NotSerializableException 抛出一个实例需要一个Serializable接口,序列化运行时或实例的类可能会抛出此异常
}
/* 写入结果
�� sr com.wang.specialdemo.Student03������� I ageL namet Ljava/lang/String;xp   t 张三
*/
  • 学生类
import java.io.Serializable;

//如何解决NotSerializableException异常
//Serializable接口 仅仅是一个标识接口 没有方法需要重写
public class Student03 implements Serializable {
    private String name;
    private int age;

    public Student03() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
3.2.4 注意事项
  • 一个对象要想被序列化,该对象所属的类必须必须实现Serializable 接口
  • Serializable是一个标记接口,实现该接口,不需要重写任何方法

3.3 对象反序列化流

3.3.1 前提
  • ObjectInputStream反序列化前 先使用ObjectOutputStream编写的原始数据和对象
3.3.2 构造方法 & 方法
构造方法说明
ObjectInputStream(InputStream in)创建从指定的InputStream读取的ObjectInputStream
方法名说明
Object readObject()从ObjectInputStream读取一个对象
3.3.3 代码示例
  • 测试类
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
//对象反序列化流
public class Demo04 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("iodemo\\demo.txt"));
        Object obj = ois.readObject();
        //向下转型
        Student03 s = (Student03) obj;
        System.out.println(s.getName() + "," + s.getAge());
        //释放资源
        ois.close();
    }
}
  • 学生类
import java.io.Serializable;

//如何解决NotSerializableException异常
//Serializable接口 仅仅是一个标识接口 没有方法需要重写
public class Student03 implements Serializable {
    private String name;
    private int age;

    public Student03() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

3.4 三个问题

3.4.1 serialVersionUID & transient的应用
  • 用对象序列化流序列化了一个对象后,假如我们修改了对象所属的类文件,读取数据会不会出问题呢?

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

    • 重新序列化

    • 给对象所属的类加一个 serialVersionUID

      • private static final long serialVersionUID = 42L;
        
  • 如何一个对象中的某个成员变量的值不想被系列化,又该如何实现?

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

      • private transient int age;
        
    • 不参与序列化过程的成员变量,输出默认值

4. Properties 集合

4.1 概述

  • 是一个Map体系的集合类
  • Properties可以保存到流中或从流中加载
  • 属性列表中的每个键及其对应的值都是一个字符串

4.2 作为Map集合使用<代码示例>

import java.util.Properties;
import java.util.Set;
// Properties作为Map集合的使用
public class Test02 {
    public static void main(String[] args) {
        //创建集合对象 Properties 木有泛型 是一个Map体系的集合类
        Properties prop = new Properties();
        //存储元素 key value
        prop.put("11111","张三");
        prop.put("22222","李四");
        prop.put("33333","王五");
        //遍历集合 输出集合元素
        Set<Object> keySet = prop.keySet();
        for (Object key : keySet) {
            Object value = prop.get(key);
            System.out.println(key + "," + value);
        }
    }
}

4.3 特有方法

方法名说明
Object setProperty(String key, String value)设置集合的键和值,都是String类型,底层调用 Hashtable方法 put
String getProperty(String key)使用此属性列表中指定的键搜索属性
Set stringPropertyNames()从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串
4.3.1 代码示例
import java.util.Properties;
import java.util.Set;

public class Demo05 {
    public static void main(String[] args) {
        Properties prop = new Properties();
        //Object setProperty(String key, String value) 底层调用的是put方法
        prop.setProperty("11111","张三");
        prop.setProperty("22222","李四");
        prop.setProperty("33333","王五");
        System.out.println(prop); //{33333=王五, 11111=张三, 22222=李四}
        //String getProperty(String key) 键找值
        System.out.println(prop.getProperty("11111")); //张三
        //Set<String> stringPropertyNames() 输出键集
        Set<String> names = prop.stringPropertyNames();
        for (String key : names) {
            String value = prop.getProperty(key);
            System.out.println(key + "," + value);
        }
    }

4.4 结合IO流的方法

4.4.1 方法
方法名说明
void load(InputStream inStream)从输入字节流读取属性列表(键和元素对)
void load(Reader reader)从输入字符流读取属性列表(键和元素对)
void store(OutputStream out, String comments)将此属性列表(键和元素对)写入此 Properties表中,以适合于使用 load(InputStream)方法的格式写入输出字节流
void store(Writer writer, String comments)将此属性列表(键和元素对)写入此 Properties表中,以适合使用 load(Reader)方法的格式写入输出字符流
4.4.2 代码示例
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

public class Demo06 {
    public static void main(String[] args) throws IOException{
        myStore();

        myLoad(); //{33333=王五, 11111=张三, 22222=李四}

    }

    private static void myLoad() throws IOException{
        Properties prop = new Properties();
        FileReader fr = new FileReader("iodemo\\demo.txt");
        prop.load(fr);
        fr.close();
        System.out.println(prop);
    }

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

        prop.setProperty("11111","张三");
        prop.setProperty("22222","李四");
        prop.setProperty("33333","王五");

        FileWriter fw = new FileWriter("iodemo\\demo.txt");
        //store();方法 集合元素 写入文件
        prop.store(fw,null);
        fw.close();
    }

4.5 案例

4.5.1 游戏次数
  • 游戏类
import java.util.Random;
import java.util.Scanner;
//猜数字游戏
public class GuessGame {
    public static void game(){
        Random r = new Random();

        int i = r.nextInt(100) + 1;

        while (true){
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入你猜的数字");
            int i1 = sc.nextInt();

            if (i > i1){
                System.out.println("小了");

            }else if (i < i1){
                System.out.println("大了");
            }else{
                System.out.println("恭喜你猜对了,正确答案为:" + i);
                break;
            }
        }
    }
}
  • 测试类
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
//游戏次数
/*
1.写一个游戏类,里面有一个猜数字的小游戏
2.写一个测试类
3.从文件中读取数据到Properties集合,用load()方法实现
	文件已经存在:game.txt
	里面有一个数据值:count=0
4.通过Properties集合获取到玩游戏的次数
5.判断次数是否到到2次了
	如果到了,给出提示:游戏试玩已结束,想玩请充值(www.itcast.cn)
	如果不到3次:
		次数+1,重新写回文件,用Properties的store()方法实现
		玩游戏
*/
public class Test {
    public static void main(String[] args) throws IOException {
        Properties pt = new Properties();
        FileReader fr = new FileReader("iodemo\\demo.txt");
        //load();方法 将文件内容存储到Properties集合中
        pt.load(fr);
        //释放资源
        fr.close();
        //getProperty();方法 键找值 
        String count = pt.getProperty("count");
        //值是数字  将String转成Int类型
        int number = Integer.parseInt(count);
        if (number>=2){
            System.out.println("你的免费游戏次数不足,请充值648继续畅玩");
        }else {
            GuessGame.game();
            number++;
            //将元素存储到集合
            pt.setProperty("count",String.valueOf(number));
            FileWriter fw = new FileWriter("iodemo\\demo.txt");
            //store();方法 将集合中元素写入文件
            pt.store(fw,null);
            fw.close();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值