(七)特殊操作流
1.标准输入流
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);
代码演示:
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 {
/*
InputStream is = System.in;
//如何把字节流转换为字符流?用转换流
InputStreamReader isr = new InputStreamReader(is);
//如何使用字符流一次读一行数据
//需要使用字符缓冲输入流的特有方法
BufferedReader br = new BufferedReader(isr);
*/
//简化上述三行代码
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入一个字符串:");
String ss = br.readLine();
System.out.println("你输入的字符串是:" + ss);
System.out.println("请输入一个整数:");
int i = Integer.parseInt(br.readLine());
System.out.println("你输入的整数为:" + i);
//这样想要的数据类型代码太麻烦了,所以Java提供了Scanner类来简化代码
Scanner sc = new Scanner(System.in);
int i1 = sc.nextInt();
}
}
(ps:当我学到这里,我感觉我整个人精神了,当这一节出现System.in时我就在想,这个东西跟InputStream什么的乱七八糟的有什么关系???学完了之后真是眼前焕然一新,Scanner 没错就是它,太牛了,绕来绕去又绕回来了,以前刚开始接触Java使用 Scanner键盘录入的时候压根没想过它到底为什么这么写,就觉得键盘录入固定格式就应该这样,随着学习的深入,很多谜团都解开了,原来万物都有个由来。太想记录此刻的心情了哈哈,这些都是我的笔记,在未来我可能会有写博客的习惯,然后将笔记一点点分享到博客中,期待未来我的粉丝们嘿嘿,继续学习了,加油!)
(泪目了家人们,上面是一年前刚学Java时傻乎乎的自己记录的感受,今天2022.9.5我也是最近开始了自己的博客创作之旅,能看到这里的不论是路人还是粉丝,谢谢你们的支持,我会继续努力,持续将我的全部Java笔记分享到博客中,以供大家学习参考)
2.标准输出流
public static final PrintStream out:标准输出流。通常该流对应于显示输出或由主机环境或用户指定的另一个输出目标
输出语句的本质:是一个标准的输出流
- PrintStream ps = System.out;
- PrintStram类有的方法,System.out都可以使用
注意:其中println方法可以没有参数,但是print方法中必须要传参,因为没有无参的print方法
代码演示:
import java.io.PrintStream;
public class SystemOutDemo {
public static void main(String[] args) {
PrintStream ps = System.out;
ps.println("hello");
ps.println();
ps.print();//此处报错,因为print方法必须要有参数
//System.out的本质是一个字节输出流
}
}
3.打印流
打印流的特点:
- 只负责输出数据,不负责读取数据
- 有自己的特有方法
(1)字节打印流(PrintStream)
- PrintStream(String fileName):使用指定的文件名创建新的打印流
- 使用继承父亲的方法写数据,查看的时候会转码;使用自己的特有方法写数据,查看的数据原样输出
代码演示:
import java.io.FileNotFoundException;
import java.io.PrintStream;
public class PrintStreamDemo {
public static void main(String[] args) throws FileNotFoundException {
PrintStream ps = new PrintStream("src\\TEMP\\TEMP28\\ps.txt");
//使用继承父亲的方法
ps.write(97);//a
//使用自己特有的方法
ps.print(97);//97
ps.println();//换行
ps.print(98);//98
ps.println(99);//99
}
}
(2)字符打印流(PrintWriter)
代码演示:
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class PrintWriterDemo {
public static void main(String[] args) throws IOException {
//PrintWriter(String FileName)
PrintWriter pw = new PrintWriter("src\\TEMP\\TEMP28\\pw.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(Writer out,boolean autoFlush)
PrintWriter pw2 = new PrintWriter(new FileWriter("src\\TEMP\\TEMP28\\pw.txt"),true);
pw.println("hello");
pw.println("world");
}
4.复制Java文件(打印流改进版)
import java.io.*;
public class CopyFileDemo {
public static void main(String[] args) throws IOException {
//创建输入流对象
BufferedReader br = new BufferedReader(new FileReader("src\\TEMP\\TEMP27\\Student.txt"));
//创建输出流对象
PrintWriter pw = new PrintWriter(new FileWriter("src\\TEMP\\TEMP28\\copyStudent.txt"),true);
//读写数据,复制文件
String line;
while((line = br.readLine())!=null){
pw.println(line);
}
//释放资源
br.close();
pw.close();
}
}
5.对象序列化流
对象序列化流:就是讲对象保存到磁盘中,或者在网路中传输对象
这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的模型、对象的数据和对象中存储的属性等信息
字节序列写到文件之后,相当于文件中持久保存了一个对象的信息
反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化
要实现序列化和反序列化就要使用对象序列化流和对象反序列化流:
- 对象序列化流:ObjectOutputStream
- 对象反序列化流:ObjectInputStream
(1)对象序列化流
对象序列化流:ObjectOutputStream
- 将Java对象的原始数据类型和图形写入OutputStream。可以使用ObjectInputStream读取(重构)对象。可以通过使用流的文件来实现对象的持久存储。如果流是网路套接字流,则可以在另一个主机上或另一个进程中重构对象
构造方法:
- ObjectOutputStream(OutputStream out):创建一个写入指定的OutStream的ObjectOutputStream
序列化对象的方法:
- void writeObject(Object obj):将指定的对象写入ObjectOutputStream
注意:
- 一个对象要想被序列化,该对象所属的类必须实现Serializable接口
- Serializable是一个标记接口,实现该接口,不需要重写任何方法
代码演示:
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class ObjectOutputStreamDemo {
public static void main(String[] args) throws IOException {
//ObjectOutputStream(OutputStream out):创建一个写入指定的OutStream的ObjectOutputStream
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("src\\TEMP\\TEMP28\\oos.txt"));
//创建对象
Student s = new Student("学生1",20);
//void writeObject(Object obj):将指定的对象写入ObjectOutputStream
oos.writeObject(s);
//释放资源
oos.close();
}
}
(2)对象反序列化流
对象反序列化流:ObjectInputStream
- ObjectInputStream反序列化先前使用ObjectOutputStream编写的原始数据和对象
构造方法
- ObjectInputStream(InputStream in):创建从指定的InputStream读取的ObjectInputStream
反序列化对象的方法:
- Object readObject():从ObjectInputStream读取一个对象
代码演示:
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class ObjectInputStreamDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//创建对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("src\\TEMP\\TEMP28\\oos.txt"));
//读取对象
Object obj = ois.readObject();
//向下转型
Student s = (Student)obj;
//输出
System.out.println(s.getName()+", "+s.getAge());
//释放资源
ois.close();
}
}
(3)对象序列化的三个问题
6.Properties
Properties概述:(Properties继承了Hashtable,Hashtable与HashMap相似)
- 是一个Map体系的集合类
- Properties可以保存到流中或从流中加载
练习:Properties作为Map集合的使用
import java.util.Properties;
import java.util.Set;
public class PropertiesDemo {
public static void main(String[] args) {
//Properties集合的构造方法中没有泛型<> 所以默认类型都是Object
Properties prop = new Properties();
//存储元素
prop.put("19103200", "学生1");
prop.put("19103201", "学生2");
prop.put("19103202", "学生3");
//遍历集合
Set<Object> keySet = prop.keySet();
for (Object key : keySet) {
Object value = prop.get(key);
System.out.println(key + ", " + value);
}
}
}
Properties集合的特有方法:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5ICutkkd-1662344106255)(https://cdn.jsdelivr.net/gh/BoBooY-GitHub/JavaSE_imgs@main/imgs/202209012120816.png)]
代码演示:
import java.util.Properties;
import java.util.Set;
public class PropertiesDemo2 {
public static void main(String[] args) {
Properties prop = new Properties();
//Object setProperty(String key,String value)
prop.setProperty("19103200", "学生1");
prop.setProperty("19103201", "学生2");
prop.setProperty("19103202", "学生3");
//Set<String> StringPropertyNames()
Set<String> names = prop.stringPropertyNames();
//遍历集合(Properties集合特有的遍历方法)
for (String key : names) {
//String getProperty(String key)
String value = prop.getProperty(key);
System.out.println(key + ", " + value);
}
}
}
7.Properties与IO流结合的方法
代码演示:
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
public class PropertiesDemo3 {
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("src\\TEMP\\TEMP28\\prop3.txt");
prop.load(fr);
fr.close();
System.out.println(prop);//{19103200=学生1, 19103201=学生2, 19103202=学生3}
}
private static void myStore() throws IOException {
Properties prop = new Properties();
//存入数据
prop.setProperty("19103200", "学生1");
prop.setProperty("19103201", "学生2");
prop.setProperty("19103202", "学生3");
//void store(Writer writer,String comments)
FileWriter fw =new FileWriter("src\\TEMP\\TEMP28\\prop3.txt");
prop.store(fw,null);//第二个参数为对文件的描述,没有描述则可以写null
fw.close();
}
}
8.案例(游戏次数)
需求:请写程序实现猜数字小游戏只能试玩3次,如果还想玩,提示:游戏试玩已结束,想玩请充值(www.BoBooY.com)
代码实现:
创建一个游戏类:
import java.util.Random;
import java.util.Scanner;
public class GuessNumber {
private GuessNumber() {
}
public static void start() {
Random r = new Random();
int num = r.nextInt(100) + 1;
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个数字:");
while (true) {
int UserNum = sc.nextInt();
if (UserNum > num) {
System.out.println("您输入的数字大了,请重新输入:");
} else if (UserNum < num) {
System.out.println("您输入的数字小了,请重新输入:");
} else if (UserNum == num) {
System.out.println("猜对了!");
break;
}
}
}
}
创建游戏测试类:
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
public class PropertiesDemo {
public static void main(String[] args) throws IOException {
//创建集合对象
Properties prop = new Properties();
//读取文件中的数据
FileReader fr = new FileReader("smallDemo\\src\\PropertiesModel\\game.txt");
prop.load(fr);
//释放资源
fr.close();
//获取count键对应的值
String count = prop.getProperty("count");
//将String类型转为int类型
int number = Integer.parseInt(count);
//判断游戏次数
if (number >= 3) {
System.out.println("试玩结束,请充值!");
} else {
GuessNumber.start();
//游戏结束,试玩次数记录加1
number++;
//将int类型数据重新打包为String类型
prop.setProperty("count",String.valueOf(number));
//将数据重新写入文件中记录保存
FileWriter fw = new FileWriter("smallDemo\\src\\PropertiesModel\\game.txt");
prop.store(fw,null);
//释放资源
fw.close();
}
}
}
其中已经存在的文件game.txt
count = 0