特殊操作流

标准输入流和标准输出流

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

public static final InputStream in
“标准”输入流。 该流已经打开,准备提供输入数据。 通常,该流对应于键盘输入或由主机环境或用户指定的另一个输入源。 
public static final PrintStream out
    “标准”输出流。 此流已经打开并准备好接受输出数据。 通常,此流对应于显示输出或由主机环境或用户指定的另一个输出目标。

输入流

  • 自己实现键盘输入:
BufferedReader br =new BufferedReader(new InputStreamReader(System.in));
  • Java提供一个键盘输入类
Scanner sc = new Scanner(System.in);
package com.io.system;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Scanner;

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);
    }
}

输出流

PrintStream ps = System.out;
  • System.out的本质是一个字节输出流
  • PrintStream类有的方法,System.out都可以使用
package com.io.system;

import java.io.PrintStream;

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();
    }
}

打印流

打印流分类:

  • 字节打印流:PrintStream
  • 字符打印流:PrintWrite

特点:

  • 只负责输出数据,不负责写数据
  • 有自己的特有方法

字节打印流

  • 使用继承父类的方法写数据,查看的时候会转码;使用自己独有数据时,查看的数据原样输出
public PrintStream(String fileName):使用指定的文件名创建新的打印流
package com.io.special.print;

import java.io.IOException;
import java.io.PrintStream;

public class PrintStreamDemo {
    public static void main(String[] args) throws IOException {
        //public PrintStream(String fileName):使用指定的文件名创建新的打印流
        PrintStream ps = new PrintStream("E:\\study\\JavaSE\\基础语法\\ps.txt");

        //写数据
        //字节输出流的方法
//        ps.write(97);

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

        //释放资源
        ps.close();
    }
}

字符打印流

构造方法

public PrintWriter(String fileName):使用指定的文件名创建一个新的PrintWriter,而不需要自动执行行刷新。
public PrintWriter(OutputStream out,boolean autoFlush):从现有的OutputStream创建一个新的PrintWriter。
 	//out - 输出流
   	//autoFlush - 一个布尔值 如果为真,则println , printf ,或format方法将刷新输出缓冲区
package com.io.special.print;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class PrintWriteDemo {
    public static void main(String[] args) throws IOException {
        //public PrintWriter(String fileName):使用指定的文件名创建一个新的PrintWriter,而不需要自动执行行刷新。
//        PrintWriter pw = new PrintWriter("E:\\study\\JavaSE\\基础语法\\pw.txt");

//        pw.write("hello");
//        pw.write("\r\n");
//        pw.flush();
//        pw.write("\r\n");
//        pw.write("world");
//        pw.flush();

//        pw.println("hello");
//        pw.println("world");
//        pw.flush();

        //public PrintWriter(OutputStream out,boolean autoFlush):从现有的OutputStream创建一个新的PrintWriter。
        //out - 输出流
        //autoFlush - 一个布尔值 如果为真,则println , printf ,或format方法将刷新输出缓冲区

//        PrintWriter pw = new PrintWriter(new FileWriter("E:\\study\\JavaSE\\基础语法\\pw.txt"),true);
        PrintWriter pw = new PrintWriter(new FileWriter("E:\\study\\JavaSE\\基础语法\\pw.txt"),false);


        pw.println("hello");
        /*
            pw.write("hello");
            pw.write("\r\n");
            pw.flush();
         */
        pw.println("world");

        pw.close();
    }
}

案例

package com.io.special.demo;

import java.io.*;

//需求:复制文件
public class CopyJavaDemo {
    public static void main(String[] args) throws IOException {
        /*
        //1.根据数据源创建字符输入流对象
        BufferedReader br = new BufferedReader(new FileReader("E:\\study\\JavaSE\\基础语法\\ps.txt"));

        //2.根据目的地创建字符输出流对象
        BufferedWriter bw = new BufferedWriter(new FileWriter("E:\\study\\JavaSE\\基础语法\\ps1.txt"));

        //3.读写数据,复制文件
        String line;
        while ((line = br.readLine())!= null){
            bw.write(line);
            bw.newLine();
            bw.flush();
        }

        br.close();
        bw.close();
         */

        //1.根据数据源创建字符输入流对象
        BufferedReader br = new BufferedReader(new FileReader("E:\\study\\JavaSE\\基础语法\\ps.txt"));

        //2.根据目的地创建字符输出流对象
        PrintWriter pw = new PrintWriter(new FileWriter("E:\\study\\JavaSE\\基础语法\\ps1.txt"),true);

        //3.读写数据,复制文件
        String line;
        while ((line = br.readLine())!= null){
            pw.println(line);
        }

        br.close();
        pw.close();
    }
}

对象序列化流

对象序列化流

对象序列化流:ObjectOutputStream

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

  • 构造方法:

public ObjectOutputStream(OutputStream out):创建一个写入指定的OutputStream的ObjectOutputStream。
  • 序列化对象的方法:
public final void writeObject(Object obj):将指定的对象写入ObjectOutputStream。
  • 注意:
    • 一个对象想要被序列化,该对象所属的类必须实现Serializable接口
    • Serializable是一个标记接口,实现该接口,不需要重写任何方法
package com.io.special.object;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class ObjectOutputStreamDemo {
    public static void main(String[] args) throws IOException {
        //public ObjectOutputStream(OutputStream out):创建一个写入指定的OutputStream的ObjectOutputStream。
        ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream("E:\\study\\JavaSE\\基础语法\\oos.txt"));

        //创建对象
        Student s = new Student("流年",22);

        //public final void writeObject(Object obj):将指定的对象写入ObjectOutputStream。
        oos.writeObject(s);
        //NotSerializableException:抛出一个实例需要一个Serializable接口。 序列化运行时或实例的类可能会抛出此异常
        //类的序列化由实现java.io.Serializable接口的类启用。 不实现此接口的类将不会使任何状态序列化或反序列化。

        //释放资源
        oos.close();
    }
}
package com.io.special.object;

import java.io.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;
    }

    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;
    }
}

对象反序列化流

  • ObjectInputStream反序列化先前使用ObjectOutputStream编写的原始数据和对象。
  • 构造方法:
public ObjectInputStream(InputStream in):创建从指定的InputStream读取的ObjectInputStream。
  • 反序列化方法:
public final Object readObject():从ObjectInputStream读取一个对象。
package com.io.special.object;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class ObjectInputStreamDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //public ObjectInputStream(InputStream in):创建从指定的InputStream读取的ObjectInputStream。
        ObjectInputStream ois = new ObjectInputStream(new
                FileInputStream("E:\\study\\JavaSE\\基础语法\\oos.txt"));

        //public final Object readObject():从ObjectInputStream读取一个对象。
        Object obj = ois.readObject();

        Student s = (Student) obj;

        System.out.println(s.getName() + "," + s.getAge());

        ois.close();

    }
}

serialVersionUID&transient

1.用对象序列化流序列化一个对象后,假如我们修改了对象所属的类文件,读取数据会不会出现问题?
    java.io.InvalidClassException:
        当序列化运行时检测到类中的以下问题之一时抛出。
            类的串行版本与从流中读取的类描述符的类型不匹配
            该类包含未知的数据类型
            该类没有可访问的无参数构造函数         

    com.io.special.object.Student; local class incompatible:
    stream classdesc serialVersionUID = 4307522101919733830,
    local class serialVersionUID = -3752805270447829666

2.如果出现问题,如何解决呢?
    给对象所属的类加一个值:private static final long serialVersionUID = 42L;

3.如果一个对象中的某个成员变量不想被序列化,又该如何实现
    给成员变量加transient关键字修饰,该关键字标记的成员变量不参与序列化过程
package com.io.special.object;

import java.io.*;

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("E:\\study\\JavaSE\\基础语法\\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("E:\\study\\JavaSE\\基础语法\\oos.txt"));

        Student s = new Student("流年",22);

        oos.writeObject(s);

        oos.close();
    }
}
package com.io.special.object;

import java.io.Serializable;

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 +
                '}';
    }
}

Properties

  • 是一个Map体系的集合类

  • Properties可以保存到流中或从流中加载

作为Map集合的使用

package com.io.special.properties;

import java.util.Properties;
import java.util.Set;

public class PropertiesDemo {
    public static void main(String[] args) {
        //创建集合对象
//        Properties<String,String> prop = new Properties<String,String>();//错误的
        Properties prop = new Properties();
        
        //存储元素
        prop.put("xuehao001","流年");
        prop.put("xuehao002","冰茶");
        prop.put("xuehao003","长岛");
        
        //遍历集合
        Set<Object> keySet = prop.keySet();
        for (Object key :keySet){
            Object value = prop.get(key);
            System.out.println(key+","+value);
        }
    }
}

特有方法

public Object setProperty(String key,String value):调用Hashtable方法put。
public String getProperty(String key):使用此属性列表中指定的键搜索属性。
public Set<String> stringPropertyNames():从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串
package com.io.special.properties;

import java.util.Properties;
import java.util.Set;

public class PropertiesDemo002 {
    public static void main(String[] args) {
        //创建集合对象
        Properties prop = new Properties();

        //public Object setProperty(String key,String value):调用Hashtable方法put 。
        prop.setProperty("xuehao001", "流年001");
        prop.setProperty("xuehao002", "流年002");
        prop.setProperty("xuehao003", "流年003");

        //public String getProperty(String key):使用此属性列表中指定的键搜索属性。
        System.out.println(prop.getProperty("xuehao001"));
        System.out.println(prop.getProperty("xuehao0011"));

        //public 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);
        }

        System.out.println(prop);
    }
}

与IO流相结合

public void store(Writer writer,String comments):将此属性列表(键和元素对)写入此Properties表格中,以适合使用load(Reader)方法的格式将输出字符流写入 。
public void load(Reader reader):以简单的线性格式从输入字符流读取属性列表(关键字和元素对)。
package com.io.special.properties;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

public class PropertiesDemo003 {
    public static void main(String[] args) throws IOException {
        //把集合中的数据保存到文件
        myStore();

        //把文件数据加载到集合
        myLoad();
    }

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

        //public void load(Reader reader):以简单的线性格式从输入字符流读取属性列表(关键字和元素对)。
        FileReader fr = new FileReader("E:\\study\\JavaSE\\基础语法\\fw.txt");
        prop.load(fr);
        fr.close();

        System.out.println(prop);
    }

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

        prop.setProperty("xuehao001", "流年001");
        prop.setProperty("xuehao002", "流年002");
        prop.setProperty("xuehao003", "流年003");

        //public void store(Writer writer,String comments):将此属性列表(键和元素对)写入此Properties表格中,以适合使用load(Reader)方法的格式将输出字符流写入 。
        FileWriter fw = new FileWriter("E:\\study\\JavaSE\\基础语法\\fw.txt");
        prop.store(fw,null);
        fw.close();

    }
}

案列

package com.io.special.properties;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

/*
    需求:写程序实现猜数字小游戏只能实现3次,如果还想玩,给出提示
 */
public class PropertiesTest {
    public static void main(String[] args) throws IOException {
        //2.从文件中读取数据到Properties集合,用load()方法实现
        //game.txt 文件已存在 里面的数据:count = 0
        Properties prop = new Properties();

        FileReader fr = new FileReader("E:\\study\\JavaSE\\基础语法\\game.txt");
        prop.load(fr);
        fr.close();

        //3.通过Properties集合获取到玩游戏的次数
        String count = prop.getProperty("count");
        int number = Integer.parseInt(count);

        //4.判断是否到达3次
        if (number>=3){
            //5.给出提示
            System.out.println("已玩3次");
        }else {
            //玩游戏
            GuessNumber.start();

            //次数加1,重新写回文件,用Properties的start()方法实现
            number++;
            prop.setProperty("count",String.valueOf(number));
            FileWriter fw = new FileWriter("E:\\study\\JavaSE\\基础语法\\game.txt");
            prop.store(fw,null);
            fw.close();
        }
    }
}
package com.io.special.properties;

import java.util.Random;
import java.util.Scanner;

//1.写一个游戏类
public class GuessNumber {
    private GuessNumber() {
    }

    public static void start(){
        //随机生成要猜的数字
        Random random = new Random();
        int number = random.nextInt(100);

        while (true){
            //键盘录入要猜的数字
            Scanner sc = new Scanner(System.in);

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

            //进行判断
            if (guessNumber>number){
                System.out.println("你猜的数字"+guessNumber+"大了");
            }else if (guessNumber<number){
                System.out.println("你猜的数字"+guessNumber+"小了");
            }else {
                System.out.println("恭喜猜中");
                break;
            }
        }
    }
}