标准输入输出流
System类中有两个静态的成员变量:
- public static final [InputStream](../../java/io/InputStream.html) in“标准”输入流。该流已经打开,准备提供输入数据。通常,该流对应于键盘输入或由主机环境或用户指定的另一个输入源。
- public static final [PrintStream](../../java/io/PrintStream.html) out“标准”输出流。此流已经打开并准备好接受输出数据。通常,此流对应于显示输出或由主机环境或用户指定的另一个输出目标。
标准输入流
- public static final [InputStream](../../java/io/InputStream.html) in“标准”输入流。该流已经打开,准备提供输入数据。通常,该流对应于键盘输入或由主机环境或用户指定的另一个输入源。
- in 是 [InputStream](../../java/io/InputStream.html)类型的 使用final修饰是一个常量 被static代表可以通过类名直接使用
public static void main(_String[] args) throws IOException {
// public static final InputStream in 标准输入流。该流对应于键盘输入或由主机环境或用户指定的另一个输入源。
// in是InputStream类型 被final 修饰说明对象是常量,被static说明可以通过类名被访问
// InputStream是字节输入流的抽象基类,采用多态完成System对定义的对象初始化
/InputStream is = System.in;
// 该字节数据来源于键盘输入
int by;
while ((by = is.read())!=-1){ System.out.print((char)by); }
// InputStream是字节流输入数据,字符流会乱码
// 使用字节流转换方法将字节流转换为字符流—InputStreamReader
InputStreamReader isr = new InputStreamReader(is);
// 使用字符流实现一次读取一行数据
// 使用字符缓冲输入流的特有方法,实现一次读取一行
BufferedReader br = new BufferedReader(isr);/
// 使用内部类简化新建对象— 底层是System.in
// 1、键盘输入的字节流
// 2、通过字符流转换成为字符缓冲输入流
// 3、使用缓冲字符流方法一次读取一行数据
BufferedReader br = new BufferedReader(new InputStreamReader(System._in));
System.out.println(“请输入一个字符串: “);
String line = br.readLine();
System.out.println(“你输入的字符串是: “ + line);
// 如果想输入数字,使用包装类转换
System.out.println(“请输入一个整数: “);
int parseInt = Integer.parseInt(_br.readLine());
System._out.println(“你输入的整数是: “ + parseInt);
// 因为自己实现键盘录入代码过于繁琐,Java提供了一个工具类Scanner类,底层代码同样是System.in
Scanner sc = new Scanner(_System._in); }
标准输出流
- public static final [PrintStream](../../java/io/PrintStream.html) out“标准”输出流。此流已经打开并准备好接受输出数据。通常,此流对应于显示输出或由主机环境或用户指定的另一个输出目标。
- out 是 PrintStream类型的 使用final修饰是一个常量 被static代表可以通过类名直接使用
public static void main(_String[] args) {
// PrintStream是OutputStream是字节输入流的抽象基类,采用多态完成System对定义的对象初始化
PrintStream ps = System._out;
// 能够方便地打印各种数据
// 不换行方法print()
ps.print(“100”);
// 换行方法println()
ps.println(“100”);
// System.out的本质是一个字节输出流
// System.out.print(); 必须含有参数,如果没有方法不能使用
System.out.println(); }
打印流
打印流分类:
- **字节打印流:PrintStream**
- **字符打印流:PrintWriter**
打印流特点:
- **子负责输出数据,不负责读取数据**
- **有自己的特有方法**
字节打印流方法—PrintStream()
- **PrintStream(String fileName): 使用指定的文件名创建新的打印流**
- **使用继承父类的方法写数据(例如:字节流的write()),查看的时候会自动转码**
- **使用PrintStream的特有方法print()写入数据,会查看原样数据**
public static void main(_String[] args) throws IOException {
// PrintStream(String fileName): 使用指定的文件名创建新的打印流
PrintStream ps = new PrintStream(“test11\text.txt”);
// 写数据,使用字节输出流方法
ps.write(97);
// 使用打印流PrintStream特有方法print()写入
ps.print(98);
// 特有换行方法println()写入
ps.println(99);
// 释放资源
ps.close();}_
字符打印流方法—PrintWriter()
- **PrintWriter(String fileName): 使用指定的文件名创建新的PrintWriter,而不需要自动执行刷新**
- **PrintWriter(Write out,boolean autoFlush):**
- **创建一个新的PrintWriter -- 两个参数(out: 字符输出流,atuoFlush: 一个布尔值类型,如果为真,则println,printf,或format方法将刷新输出缓冲区)**
public static void main(_String[] args) throws IOException {
// PrintWriter(String fileName): 使用指定的文件名创建新的PrintWriter,而不需要自动执行
PrintWriter pw = new PrintWriter(“D:\PgProject\test11\test.txt”);
// 使用字符输入流方法写入,使用\r\n进行换行
pw.write(“hello”);
pw.write(“\r\n”);
// 因为字符缓冲流输入方法无法直接写入文件,需要执行刷新操作才被执行
pw.flush();
// pw.close();
// 使用字符打印流特殊方法println()写入
// 可以不用在写入\r\n直接实现换行
pw.println(“hello”);
// 但是同样是写入字符,需要通过flush()刷新后写入
pw.flush()_;
// PrintWriter(Write out,boolean autoFlush) 判断是否为字符流,如果是直接输出,不用flush()<br /> PrintWriter pw1 = new PrintWriter_(_new FileWriter_(_"D:\\PgProject\\test11\\test.txt"_)_,true_)_;<br /> // out: 字符输出流对象(new FileWriter("fileName")),autoFlush: 一个布尔值类型<br /> pw1.println_(_"hello"_)_;<br /> // 释放资源<br /> pw.close_()_;<br /> pw1.close_()_; _}_
案例: 复制Java文件(打印流方法)
需求:把模块目录下的java文件内容复制到Copy.java文件中
思路:
1. 根据数据创建字符打印输入流对象
1. 根据目的地创建字符打印输出流对象
1. 读写数据,复制文件
1. 释放资源
public static void main(_String[] args) throws IOException {
// 根据数据创建字符输入流对象
// 数据源是需要读取数据所以使用缓冲字符流Reader
BufferedReader br = new BufferedReader(new FileReader(“D:\PgProject\test11\src\com_24\SystemInDemo.java”));
// 根据目的地创建字符输出流对象
// 数据源是需要复制数据所以使用缓冲字符流Writer
BufferedWriter bw = new BufferedWriter(new FileWriter(“D:\PgProject\test11\Copy.java”));
// 读写数据,复制文件,缓冲流输出对象基础写入数据三步
String line;
while ((line = br.readLine())!= null){
bw.write(line);
bw.newLine();
bw.flush(); }
// 使用打印流写入优化代码println();
PrintWriter pw = new PrintWriter(new FileWriter(“D:\PgProject\test11\Copy.java”),true);
// 读写数据,复制文件
String line;
while ((line = br.readLine())!= null){
// 使用打印流写入,省略三个步骤__ _pw.println(line); }
// 释放资源
// bw.close();
pw.close();
br.close(); }_
对象序列化流
对象序列化:就是将对象保存到磁盘中,或者在网络中传输对象
1. **这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的类型、对象的数据和对象中存储的属性等信息字节序列写到文件之后,相当于文件中持久保存了一个对象的信息**
1. **反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化**
对象序列化需要通过两个类实现
1. **对象序列化流:ObjectOutputStream**
1. **对象反序列化流: ObjectInputSteram**
对象序列化流:ObjectOutputStream
public abstract class ObjectOutputStream
extends OutputStream 具体的类继承OutputStream字节输出流类
implements ObjectOutput, ObjectStreamConstants 实现了ObjectOutput, ObjectStreamConstants接口
介绍:
1. ObjectOutputStream将Java对象的原始数据类型和图形写入OutputStream。
1. 可以使用ObjectInputStream读取(重构)对象。
1. 可以通过使用流的文件来实现对象的持久存储。 如果流是网络套接字流,则可以在另一个主机上或另一个进程中重构对象。
构造方法:
1. ObjectOutputStream(OutputStream out): 创建一个写入指定的OutputStream的ObjectOutputStream。
1. ObjectOutputStream() :为完全重新实现ObjectOutputStream的子类提供一种方法,不必分配刚刚被ObjectOutputStream实现使用的私有数据
序列化对象方法:
1. writeObject(Object obj) :将指定的对象写入ObjectOutputStream。
注意:
1. 一个对象想要被序列化,该对象必须实现Serializable接口
1. Serializable是一个标记接口(实现普通接口需要重写方法),标记接口没有方法,只做声明该对象可以被序列化
代码实现:
public class ObjectOutputStreamDemo {
_public static void main(String[] args) throws IOException {
// ObjectOutputStreamDemo(OutputStream out)
// 创建一个写入指定的OutputStream的ObjectOutputStream
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(“D:\PgProject\test11\test.txt”));
// 对象序列化需要一个实例化的对象
Student s = new Student(“李畅”,23);
Student s1 = new Student(“唐明”,22);
// 序列化对象方法:writeObject(Object obj)
// 将指定的对象写入ObjectOutputStream文件
// 写入的对象必须implements Serializable接口,声明该类可以被序列化才能使用
// 因为写入的是序列化,所以无法读取内容,需要通过反序列化读取
oos.writeObject(s);
oos.writeObject(s1);
// 释放资源
oos.close(); } }
———————————————————————————————————
// 创建一个对象
// 执行报错NotSerializableException:抛出一个实例需要一个Serializable接口。
// 序列化运行时或实例的类可能会抛出此异常。 参数应该是类的名称
// public interface Serializable类的序列化由实现java.io.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; }
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; } }_
对象反序列化流: ObjectInputSteram
public class ObjectInputStream
extends InputStream 具体的类继承InputStream 字节输入流类
implements ObjectInput, ObjectStreamConstants
介绍:
- ObjectInputStream反序列化先前使用ObjectOutputStream编写的原始数据和对象
构造方法:
ObjectInputStream(InputStream in) :创建从指定的InputStream读取的ObjectInputStream。
反序列化对象方法:
Object readObject() :从ObjectInputStream读取一个对象。
代码实现:
public static void main(_String[] args) throws IOException, ClassNotFoundException {
// 创建对象反序列化流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(“D:\PgProject\test11\test.txt”));
// 调用对象反序列化流方法readObject()
Object obj = ois.readObject();
// 已知该对象为学生对象,可以使用Object类向下转型
// 因为Object是父类,Student是子类所以是向下转型—(Student)obj;
Student student = (Student) obj;
System._out.println(_student.getName()+”,”+student.getAge()); // 李畅,23
// 释放反序列化流
ois.close(); }_
对象序列化流三个问题
三个问题:
1. **用对象序列化了一个对象后,假如修改了对象所属的类文件,读取数据会不会出问题?**
1. **如果出现问题,如何解决?**
1. **如果该对象中的某个成员变量的值不想被序列化,如何实现呢?**
解决方案:
1. **用对象序列化了一个对象后,假如修改了对象所属的类文件,读取数据会不会出问题?**
1. 会出现问题
4. **如果出现问题,如何解决?**
1. 如果出现InvalidClassException问题
1. 需要给被序列化声明的类添加序列化的serialVersionUID确保地址一致
1. private static final long _serialVersionUID _= 42L;
5. **如果该对象中的某个成员变量的值不想被序列化,如何实现呢?**
1. **可以将不想被序列化的成员变量添加transient修饰符**
1. java 的transient关键字为我们提供了便利,你只需要实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。
1. private transient int age;
Properties 类
Properties概述:
1. 继承Hashtable本质上是一个Map体系的集合类
1. Properties可以保存在流中或者从流中加载
Properties作为Map集合的使用:
public static void main(_String[] args) {
// 创建集合对象—底层是Map集合
// Map集合是两个泛型参数一个key一个是value但Properties没有泛型规范
// Properties
Properties ppt = new Properties
// 存储元素,使用Map集合的put()添加元素
ppt.put(“01”, “李畅”);
ppt.put(“02”, “赵明”);
ppt.put(“03”, “唐明”);
// 遍历Map集合方法,获取键keySet()
// 没有指定Map泛型,所以都是Object类
Set<_Object_> keySet = ppt.keySet();
// 遍历获取的键,通过键获取值get(),使用增强for
for (Object key : keySet) {
Object value = ppt.get(key);
System._out.println(_key + “,” + value); } }_
Properties作为Map集合的特有方法:
public Object setProperty(String key, String value)
底层是Hashtable方法put 。 强制使用字符串的属性键和值都是String。
public String getProperty(String key)
用此属性列表中指定的键搜索值。
public Set
返回此属性列表中的一组键,其中键及其对应的值为字符串
public static void main(_String[] args) {
// 创建集合对象Properties
Properties ppt = new Properties();
// public Object setProperty(String key, String value)
// 底层Hashtable方法put ,ctrl+b 下钻代码查看源码
// 强制使用字符串的属性键和值都是String。
/ setProperty(String key, String value) { return put(key, value); }
put(K key, V value) { return map.put(key,value) }
/
ppt.setProperty(“001”,”李畅”);
ppt.setProperty(“002”,”赵明”);
ppt.setProperty(“003”,”唐明”);
// String getProperty(String key) 根据传递的键找对应的值
System._out.println( _ppt.getProperty(“001”)); // 李畅
// Set
// 返回此属性列表中的一组键的集合,其中键及其对应的值为字符串
Set
for (String keyNames: propertyNames){
// 使用Properties的特有方法根据键获得值
String valueNames = ppt.getProperty(keyNames);
System._out.println(_keyNames+”,”+valueNames); } }_
Properties作为集合和IO流结合的方法:
两个特有方法:load() 和 store()
void load(InputStream inStream)
从输入字节流读取属性列表(键和元素对)
void load(Reader reader)
从输入字符流读取属性列表(关键字和元素对)
void store(OutputStream out, String comments)
将此属性列表(键和元素对)写入此 Properties表中,以适合于使用 load(InputStream)方法加载到 Properties表中的格式输出字节流
void store(Writer writer, String comments)
将此属性列表(键和元素对)写入此 Properties表中,以适合使用 load(Reader)方法的格式输出到输出字符流
public static void main(_String[] args) throws IOException {
// 把集合中的数据保存到文件中,创建方法store()
_myStore();
// 把文件中的数据加载到集合
myLoad();}
_private static void myStore() throws IOException {
Properties ppt = new Properties();
// 使用Properties特有添加方法setProperty()
ppt.setProperty(“001”,”李畅”);
ppt.setProperty(“002”,”赵明”);
ppt.setProperty(“003”,”唐明”);
// void store(Writer writer, String comments)
// 将此属性列表(键和元素对)写入此 Properties表中,以适合使用 load(Reader)方法的格式输出到输出字符流
FileWriter fw = new FileWriter(“D:\PgProject\test11\test.txt”);
// void store(Writer writer, String comments)
// 将此属性列表(键和元素对)写入此 Properties表中,以适合使用 load(Reader)方法的格式输出到输出字符流
// 两个参数: Writer参数是需要读写的数据列表, comments参数是描述信息
ppt.store(fw,”牛逼”);
// 释放资源
fw.close();}
private static void myLoad() throws IOException {
Properties ppt = new Properties();
// void load(Reader reader)
// 从输入字符流读取属性列表(关键字和元素对)
FileReader fr = new FileReader(“D:\PgProject\test11\test.txt”);
ppt.load(fr);
// 释放资源
fr.close();
System._out.println(_ppt); // {003=唐明, 002=赵明, 001=李畅}}_
案例:游戏次数
需求:使用程序实现猜数字小游戏只能试玩3次,如果还想晚,提示:试玩结束,请充值
思路:
1. 写一个游戏类, 里面有一个猜数字的小游戏
1. 写一个测试类, 测试类中有main()方法, main()方法中按照下面步骤完成:
1. 从文件中读取数据到Properties集合, 用load()方法实现
1. 文件已经存在: game.txt
1. 里面有一个数据值: count = 0
2. 通过Properties集合获取到玩游戏的次数
2. 判断游戏次数是否到3次
1. 如果到了, 给出提示: 游戏试玩已经结束, 请充值
1. 如果不到3次:
1. 继续玩游戏
1. 次数+1, 重新协会晚间,用Properties的store()方法实现
代码实现:
// 创建一个游戏类
public class GuessGame {
_private GuessGame(){ }
// 该方法通过static修饰,其他类可以直接使用该类的类名调用
public static void start(){
// 要完成猜数字的游戏,首先需要有一个要猜的数字,使用随机数生产该数字,范围1到100
Random r = new Random();
// 设置nextInt范围100,+1是为了从1开始,不是从0
int number = r.nextInt(100)+1;
// 使用while(true) 死循环
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语句终结while死循环
break; } } } }
————————————————————————————————-
public class PropertiesTest01 {
_public static void main(String[] args) throws IOException {
// 从文件中读取数据到Properties集合, 用load()方法实现
Properties ppt = new Properties();
// 读取文件内容,使用Properties集合方法load()读取
FileReader fr = new FileReader(“D:\PgProject\test11\game.txt”);
ppt.load(fr);
fr.close();
// 通过Properties集合获取到玩游戏的次数getProperty()
String count = ppt.getProperty(“count”);
// 因为是字符互类型,使用Integer.parseInt()转换
int number = Integer._parseInt(_count);
if (number >= 3){
System._out.println(“次数已到,请充值”);
}_else {
// 继续玩游戏,因为start()使用static修饰,通过该类名直接调用
GuessGame._start();
// 次数+1, 重新协会晚间,用Properties的store()方法实现
number++;
// 通过Properties集合的添加方法,因为必须为String使用String.value()方法转换
ppt.setProperty(“count”, String.valueOf(_number));
// 重新写到文件中,用Properties的store()方法实现
FileWriter fw = new FileWriter(“D:\PgProject\test11\game.txt”);
ppt.store(fw,”次数+1”);
fw.close();
System._out.println(“游戏结束”); } } }
代码逻辑理解:
1、创建游戏类使用static修饰,可以直接通过类名调用方法
2、使用Random类的随机数,使用Random的nextInt()方法获取下一个随机数并设置范围1-100
3、 使用Scanner类使用nextInt(System.in)方法录入键盘输入数字
4、 使用while(true)死循环对比数字是否一致,一致后使用break结束循环
5、使用Properties集合读取文件,创建Properties集合对象
6、使用FileReader输出字符流读取文件内容
7、使用Properties集合特有方法load(),获取FileReader输出字符流的数据
8、通过Properties的特有方法getProperties()获取文件中的键对应的值
9、因为Properties的键值对强行为String需要进行包装类转换类型
10、 判断游戏的次数,根据Properties的键count获取的值
11、初始count为0可以继续玩耍,但是每次循环结束后游戏的次数+1
12、如何实现次数+1,游戏结束后重写入文件中count+1将count的数字写入文件
13、使用Properties集合中的stroe()实现重写数据,count就会根据if的判断改变
14、一旦if的判断中的number为3 count就为3 游戏结束