Java(35)IO特殊操作流&Properties集合

时间:2025-04-14 11:04:25

作者:季沐测试笔记

原文地址https://www.cnblogs.com/testero/p/15228454.html

博客主页https://www.cnblogs.com/testero

1.IO特殊操作流

1.1标准输入流

  • System类中有两个静态的成员变量

    • public static final InputStream in:标准输入流。通常该流对应于键盘输入或由主机环境或用户指定的另一个输入源
    • public static final PrintStream out:标准输出流。通常该流对应于显示输出或由主机环境或用户指定的另一个输出目标
  • 自己实现键盘录入数据

    public class SystemInDemo {
    public static void main(String[] args) throws IOException {
    //public static final InputStream in:标准输入流
    // InputStream is = System.in; // int by;
    // while ((by=is.read())!=-1) {
    // System.out.print((char)by);
    // } //如何把字节流转换为字符流?用转换流
    // InputStreamReader isr = new InputStreamReader(is);
    // //使用字符流能不能够实现一次读取一行数据呢?可以
    // //但是,一次读取一行数据的方法是字符缓冲输入流的特有方法
    // BufferedReader br = new BufferedReader(isr); 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.2标准输出流

  • System类中有两个静态的成员变量

    • public static final InputStream in:标准输入流。通常该流对应于键盘输入或由主机环境或用户指定的另一个输入源
    • public static final PrintStream out:标准输出流。通常该流对应于显示输出或由主机环境或用户指定的另一个输出目标
  • 输出语句的本质:是一个标准的输出流

    • PrintStream ps = System.out;
    • PrintStream类有的方法,System.out都可以使用
  • 示例代码

    public class SystemOutDemo {
    public static void main(String[] args) {
    //public static final PrintStream out:标准输出流
    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();
    }
    }

1.3字节打印流

  • 打印流分类

    • 字节打印流:PrintStream
    • 字符打印流:PrintWriter
  • 打印流的特点

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

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

    • 使用继承父类的方法写数据,查看的时候会转码;使用自己的特有方法写数据,查看的数据原样输出

    • 可以改变输出语句的目的地

      ​ public static void setOut(PrintStream out):重新分配“标准”输出流

  • 示例代码

    public class PrintStreamDemo {
    public static void main(String[] args) throws IOException {
    //PrintStream(String fileName):使用指定的文件名创建新的打印流
    PrintStream ps = new PrintStream("myOtherStream\\ps.txt"); //写数据
    //字节输出流有的方法
    // ps.write(97); //使用特有方法写数据
    // ps.print(97);
    // ps.println();
    // ps.print(98);
    ps.println(97);
    ps.println(98); //释放资源
    ps.close();
    }
    }

1.4字符打印流

  • 字符打印流构造房方法

    方法名 说明
    PrintWriter(String fileName) 使用指定的文件名创建一个新的PrintWriter,而不需要自动执行刷新
    PrintWriter(Writer out, boolean autoFlush) 创建一个新的PrintWriter out:字符输出流 autoFlush: 一个布尔值,如果为真,则println , printf ,或format方法将刷新输出缓冲区
  • 示例代码

    public class PrintWriterDemo {
    public static void main(String[] args) throws IOException {
    //PrintWriter(String fileName) :使用指定的文件名创建一个新的PrintWriter,而不需要自动执行行刷新
    // PrintWriter pw = new PrintWriter("myOtherStream\\pw.txt"); // pw.write("hello");
    // pw.write("\r\n");
    // pw.flush();
    // pw.write("world");
    // pw.write("\r\n");
    // pw.flush(); // pw.println("hello");
    /*
    pw.write("hello");
    pw.write("\r\n");
    */
    // pw.flush();
    // pw.println("world");
    // pw.flush(); //PrintWriter(Writer out, boolean autoFlush):创建一个新的PrintWriter
    PrintWriter pw = new PrintWriter(new FileWriter("myOtherStream\\pw.txt"),true);
    // PrintWriter pw = new PrintWriter(new FileWriter("myOtherStream\\pw.txt"),false); pw.println("hello");
    /*
    pw.write("hello");
    pw.write("\r\n");
    pw.flush();
    */
    pw.println("world"); pw.close();
    }
    }

1.5复制Java文件打印流改进版

  • 案例需求

    • 把模块目录下的PrintStreamDemo.java 复制到模块目录下的 Copy.java
  • 分析步骤

    • 根据数据源创建字符输入流对象
    • 根据目的地创建字符输出流对象
    • 读写数据,复制文件
    • 释放资源
  • 代码实现

    public class CopyJavaDemo {
    public static void main(String[] args) throws IOException {
    /*
    //根据数据源创建字符输入流对象
    BufferedReader br = new BufferedReader(new FileReader("myOtherStream\\PrintStreamDemo.java"));
    //根据目的地创建字符输出流对象
    BufferedWriter bw = new BufferedWriter(new FileWriter("myOtherStream\\Copy.java")); //读写数据,复制文件
    String line;
    while ((line=br.readLine())!=null) {
    bw.write(line);
    bw.newLine();
    bw.flush();
    } //释放资源
    bw.close();
    br.close();
    */ //根据数据源创建字符输入流对象
    BufferedReader br = new BufferedReader(new FileReader("myOtherStream\\PrintStreamDemo.java"));
    //根据目的地创建字符输出流对象
    PrintWriter pw = new PrintWriter(new FileWriter("myOtherStream\\Copy.java"),true); //读写数据,复制文件
    String line;
    while ((line=br.readLine())!=null) {
    pw.println(line);
    } //释放资源
    pw.close();
    br.close();
    }
    }

1.6对象序列化流

  • 对象序列化介绍

    • 对象序列化:就是将对象保存到磁盘中,或者在网络中传输对象
    • 这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的类型、对象的数据和对象中存储的属性等信息
    • 字节序列写到文件之后,相当于文件中持久保存了一个对象的信息
    • 反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化
  • 对象序列化流: ObjectOutputStream

    • 将Java对象的原始数据类型和图形写入OutputStream。 可以使用ObjectInputStream读取(重构)对象。 可以通过使用流的文件来实现对象的持久存储。 如果流是网络套接字流,则可以在另一个主机上或另一个进程中重构对象
  • 构造方法

    方法名 说明
    ObjectOutputStream(OutputStream out) 创建一个写入指定的OutputStream的ObjectOutputStream
  • 序列化对象的方法

    方法名 说明
    void writeObject(Object obj) 将指定的对象写入ObjectOutputStream
  • 示例代码

    • 学生类

      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;
      } 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;
      } @Override
      public String toString() {
      return "Student{" +
      "name='" + name + '\'' +
      ", age=" + age +
      '}';
      }
      }
    • 测试类

      public class ObjectOutputStreamDemo {
      public static void main(String[] args) throws IOException {
      //ObjectOutputStream(OutputStream out):创建一个写入指定的OutputStream的ObjectOutputStream
      ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("myOtherStream\\oos.txt")); //创建对象
      Student s = new Student("林青霞",30); //void writeObject(Object obj):将指定的对象写入ObjectOutputStream
      oos.writeObject(s); //释放资源
      oos.close();
      }
      }
  • 注意事项

    • 一个对象要想被序列化,该对象所属的类必须必须实现Serializable 接口
    • Serializable是一个标记接口,实现该接口,不需要重写任何方法

1.7对象反序列化流

  • 对象反序列化流: ObjectInputStream

    • ObjectInputStream反序列化先前使用ObjectOutputStream编写的原始数据和对象
  • 构造方法

    方法名 说明
    ObjectInputStream(InputStream in) 创建从指定的InputStream读取的ObjectInputStream
  • 反序列化对象的方法

    方法名 说明
    Object readObject() 从ObjectInputStream读取一个对象
  • 示例代码

    public class ObjectInputStreamDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
    //ObjectInputStream(InputStream in):创建从指定的InputStream读取的ObjectInputStream
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("myOtherStream\\oos.txt")); //Object readObject():从ObjectInputStream读取一个对象
    Object obj = ois.readObject(); Student s = (Student) obj;
    System.out.println(s.getName() + "," + s.getAge()); ois.close();
    }
    }

1.8serialVersionUID&transient

  • serialVersionUID

    • 用对象序列化流序列化了一个对象后,假如我们修改了对象所属的类文件,读取数据会不会出问题呢?
      • 会出问题,会抛出InvalidClassException异常
    • 如果出问题了,如何解决呢?
      • 重新序列化
      • 给对象所属的类加一个serialVersionUID
        • private static final long serialVersionUID = 42L;
  • transient

    • 如果一个对象中的某个成员变量的值不想被序列化,又该如何实现呢?
      • 给该成员变量加transient关键字修饰,该关键字标记的成员变量不参与序列化过程
  • 示例代码

    • 学生类

      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;
      } 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;
      } // @Override
      // public String toString() {
      // return "Student{" +
      // "name='" + name + '\'' +
      // ", age=" + age +
      // '}';
      // }
      }
    • 测试类

      public class ObjectStreamDemo {
      public static void main(String[] args) throws IOException, ClassNotFoundException {
      // write();
      read();
      } //反序列化
      private static void read() throws IOException, ClassNotFoundException {
      ObjectInputStream ois = new ObjectInputStream(new FileInputStream("myOtherStream\\oos.txt"));
      Object obj = ois.readObject();
      Student s = (Student) obj;
      System.out.println(s.getName() + "," + s.getAge());
      ois.close();
      } //序列化
      private static void write() throws IOException {
      ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("myOtherStream\\oos.txt"));
      Student s = new Student("林青霞", 30);
      oos.writeObject(s);
      oos.close();
      }
      }

2.Properties集合

2.1Properties作为Map集合的使用

  • Properties介绍

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

    public class PropertiesDemo01 {
    public static void main(String[] args) {
    //创建集合对象
    // Properties<String,String> prop = new Properties<String,String>(); //错误
    Properties prop = new Properties(); //存储元素
    prop.put("test001", "林青霞");
    prop.put("test002", "张曼玉");
    prop.put("test003", "王祖贤"); //遍历集合
    Set<Object> keySet = prop.keySet();
    for (Object key : keySet) {
    Object value = prop.get(key);
    System.out.println(key + "," + value);
    }
    }
    }

2.2Properties作为Map集合的特有方法

  • 特有方法

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

    public class PropertiesDemo02 {
    public static void main(String[] args) {
    //创建集合对象
    Properties prop = new Properties(); //Object setProperty(String key, String value):设置集合的键和值,都是String类型,底层调用Hashtable方法put
    prop.setProperty("test001", "林青霞");
    /*
    Object setProperty(String key, String value) {
    return put(key, value);
    } Object put(Object key, Object value) {
    return map.put(key, value);
    }
    */
    prop.setProperty("test002", "张曼玉");
    prop.setProperty("test003", "王祖贤"); //String getProperty(String key):使用此属性列表中指定的键搜索属性
    // System.out.println(prop.getProperty("test001"));
    // System.out.println(prop.getProperty("test0011")); // System.out.println(prop); //Set<String> stringPropertyNames():从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串
    Set<String> names = prop.stringPropertyNames();
    for (String key : names) {
    // System.out.println(key);
    String value = prop.getProperty(key);
    System.out.println(key + "," + value);
    }
    }
    }

2.3Properties和IO流相结合的方法

  • 和IO流结合的方法

    方法名 说明
    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)方法的格式写入输出字符流
  • 示例代码

    public class PropertiesDemo03 {
    public static void main(String[] args) throws IOException {
    //把集合中的数据保存到文件
    // myStore(); //把文件中的数据加载到集合
    myLoad(); } private static void myLoad() throws IOException {
    Properties prop = new Properties(); //void load(Reader reader):
    FileReader fr = new FileReader("myOtherStream\\fw.txt");
    prop.load(fr);
    fr.close(); System.out.println(prop);
    } private static void myStore() throws IOException {
    Properties prop = new Properties(); prop.setProperty("test001","林青霞");
    prop.setProperty("test002","张曼玉");
    prop.setProperty("test003","王祖贤"); //void store(Writer writer, String comments):
    FileWriter fw = new FileWriter("myOtherStream\\fw.txt");
    prop.store(fw,null);
    fw.close();
    }
    }

2.4游戏次数案例

  • 案例需求

    • 实现猜数字小游戏只能试玩3次,如果还想玩,提示:游戏试玩已结束,想玩请充值(www.cnblogs.com/testero)
  • 分析步骤

    1. 写一个游戏类,里面有一个猜数字的小游戏

    2. 写一个测试类,测试类中有main()方法,main()方法中写如下代码:

      ​ 从文件中读取数据到Properties集合,用load()方法实现

      ​ 文件已经存在:game.txt

      ​ 里面有一个数据值:count=0

      ​ 通过Properties集合获取到玩游戏的次数

      ​ 判断次数是否到到3次了

      ​ 如果到了,给出提示:游戏试玩已结束,想玩请充值(www.cnblogs.com/testero)

      ​ 如果不到3次:次数+1,重新写回文件,用Properties的store()方法实现玩游戏

  • 代码实现

    public class PropertiesTest {
    public static void main(String[] args) throws IOException {
    //从文件中读取数据到Properties集合,用load()方法实现
    Properties prop = new Properties(); FileReader fr = new FileReader("myOtherStream\\game.txt");
    prop.load(fr);
    fr.close(); //通过Properties集合获取到玩游戏的次数
    String count = prop.getProperty("count");
    int number = Integer.parseInt(count); //判断次数是否到到3次了
    if(number >= 3) {
    //如果到了,给出提示:游戏试玩已结束,想玩请充值(www.cnblogs.com/testero)
    System.out.println("游戏试玩已结束,想玩请充值(www.cnblogs.com/testero)");
    } else {
    //玩游戏
    GuessNumber.start(); //次数+1,重新写回文件,用Properties的store()方法实现
    number++;
    prop.setProperty("count",String.valueOf(number));
    FileWriter fw = new FileWriter("myOtherStream\\game.txt");
    prop.store(fw,null);
    fw.close();
    }
    }
    }