黑马程序员全套Java教程_Java基础教程_IO流之特殊操作流(三十三)
4.1 标准输入输出流
System类中有两个静态的成员变量: (1)public static final InputStream in:标准输入流。通常该流对应于键盘输入或由主机环境或用户指定的另一个输入源; (2)public static final PrintStream out:标准输出流。通常该流对应于键盘输出或由主机环境或用户指定的另一个输出目标。 自己实现键盘录入数据:
BufferedReader br = new BufferedReader ( new InputStreamReader ( System . in) ) ;
写起来太麻烦,Java就提供了一个类实现键盘录入:
Scanner sc = new Scanner ( System . in) ;
public static void main ( String [ ] args) throws IOException {
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) ;
Scanner sc = new Scanner ( System . in) ;
}
输出的本质:是一个标准的输出流 (1)PrintStream ps = System.out; (2)PrintStream类有的方法,System.out都可以使用。
public static void main ( String [ ] args) {
PrintStream ps = System . out;
System . out. println ( "hello" ) ;
System . out. println ( 100 ) ;
System . out. println ( ) ;
}
4.2 打印流
打印流分类:字节打印流PrintStream和字符打印流PrintWriter。 打印流的特点: (1)只负责输出数据,不负责读取数据; (2)有自己的特殊方法。 字节打印流: (1)PrintStream(String fileName):使用指定的文件名创建新的打印流; (2)使用继承父类的方法(write())写数据,查看的时候会转码;使用自己的特有方法写数据,查看的数据原样输出。
public static void main ( String [ ] args) throws FileNotFoundException {
PrintStream ps = new PrintStream ( "mySpecialStream.txt" ) ;
ps. write ( 97 ) ;
ps. println ( 97 ) ;
ps. println ( 98 ) ;
ps. close ( ) ;
}
方法名 说明 PrintWriter(String fileName) 使用会的那个的文件名创建一个新的PrintWriter,而不需要自动执行刷新 PrintWriter(Writer out, boolean autoFlush) 创建一个新的PrintWriter。out为字符字符输出流;autoFlush为一个布尔值,如果为真,则println、printf或format方法将刷新输出缓冲区
public static void main ( String [ ] args) throws IOException {
PrintWriter pw2 = new PrintWriter ( new FileWriter ( "mySpecialStream.txt" ) , true ) ;
pw2. println ( "hello" ) ;
pw2. println ( "world" ) ;
pw2. close ( ) ;
}
案例:复制Java文件(打印流改进版)
把模块目录下的PrintStreamDemo.java复制到模块目录下的Copy.java。 思路: (1)根据数据源创建字符输入流对象; (2)根据目的地创建字符输出流对象; (3)读写数据,复制文件; (4)释放资源。
public static void main ( String [ ] args) throws IOException {
BufferedReader br = new BufferedReader ( new FileReader ( "src\\itheima2\\PrintStreamDemo.java" ) ) ;
PrintWriter ps = new PrintWriter ( new FileOutputStream ( "Copy.java" ) , true ) ;
String line;
while ( ( line= br. readLine ( ) ) != null ) {
ps. println ( line) ;
}
br. close ( ) ;
ps. close ( ) ;
}
4.3 对象序列化流
对象序列化:就是将对象保存到磁盘中,或者在网络中传输对象。这种机制就是使用一个字节序列表示一个对象,该字节序列包括对象的类型、对象的数据和对象中存储的属性等信息。字节序列写到文件之后,相当于文件中持久保存了一个对象的信息。反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。要实现序列化和反序列化就要使用对象序列化流 和对象反序列化流 。 对象序列化流ObjectOutputStream: (1)对象序列化流将Java对象的原始数据类型和图形写入OutputStream,可以使用ObjectInputStream读取(重构)对象。它通过使用流的文件来实现对象的持久存储。如果是网络套接字流,则可以在另一个主机上或另一个进程中重构对象。 (2)构造方法:ObjectOutputStream(OutputStream out),创建一个将数据写入指定OutputStream的ObjectOutputStream。 (3)序列化对象的方法:void writeObject(Object obj):将指定的对象写入ObjectOutputStream。 (4)注意:一个对象想要被序列化,该对象所属的类必须实现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;
}
@Override
public String toString ( ) {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}' ;
}
public static void main ( String [ ] args) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream ( new FileOutputStream ( "Copy.java" ) ) ;
Student s = new Student ( "liubei" , 11 ) ;
oos. writeObject ( s) ;
oos. close ( ) ;
}
对象反序列化流ObjectInputStream: (1)ObjectInputStream反序列化先前使用ObjectOutputStream编写的原始数据和对象; (2)ObjectInputStream(InputStream in):创建一个从指定InputStream读取数据的ObjectInputStream; (3)反序列化对象的方法:Object readObject(),从ObjectInputStream读取一个对象。
public class ObjectInputStreamDemo {
public static void main ( String [ ] args) throws IOException , ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream ( new FileInputStream ( "Copy.java" ) ) ;
Object obj = ois. readObject ( ) ;
System . out. println ( ( Student ) obj) ;
ois. close ( ) ;
}
}
用对象序列化程序序列化一个对象后,加入我们修改了对象所属的类的文件,读数据会不会出问题呢?如果出问题了,如何解决呢? 会出问题,抛出InvalidClassException 异常。解决方法是给对象所属的类加一个serialVersionUID ,如private static final long serialVersionUID = 42L。 如果一个对象中的某个成员变量的值不想被序列化,又如何实现呢? 给该成员变量加transient 关键字修饰,该关键字标记的成员变量不参与序列化过程。如private transient int age。
public class Student implements Serializable {
private static final long serialVersionUID = 42L ;
private String name;
private transient int age;
public Student ( ) {
}
public Student ( String name, int age) {
this . name = name;
this . age = age;
}
. . . . . . . . . . . . . . . .
public static void main ( String [ ] args) throws IOException , ClassNotFoundException {
write ( ) ;
}
private static void write ( ) throws IOException , ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream ( new FileInputStream ( "Copy.java" ) ) ;
Object obj = ois. readObject ( ) ;
Student s = ( Student ) obj;
System . out. println ( "Student{" +
"name='" + s. getName ( ) + '\'' +
", age=" + s. getAge ( ) +
'}' ) ;
ois. close ( ) ;
}
private static void read ( ) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream ( new FileOutputStream ( "Copy.java" ) ) ;
Student s = new Student ( "liubei" , 11 ) ;
oos. writeObject ( s) ;
oos. close ( ) ;
}
面试题:下面哪个流输入面向字符的输入流?
(A)InputStreamReader (B)BufferedWriter (C)FileInputStream (D)ObjectInputStreamBufferedWriter为字符缓冲输出流; FileInputStream为字节输入流;ObjectInputStream为对象反序列化流。
4.4 Properties
Properties概述:是一个Map体系的集合,可以保存到流中或者从流中加载。 Propertie作为Map集合的使用:
public static void main ( String [ ] args) {
Properties prop = new Properties ( ) ;
prop. put ( "liubei" , 22 ) ;
prop. put ( "guanyu" , 21 ) ;
prop. put ( "zhangfei" , 11 ) ;
Set < Object > keySet = prop. keySet ( ) ;
for ( Object key : keySet) {
Object value = prop. get ( key) ;
System . out. println ( key + "," + value) ;
}
}
方法名 说明 Object setProperty(String key, String value) 设置集合的键和值,都是String类型,底层调用Hashtable方法put String getProperty(String key) 使用此属性列表中指定的键搜索属性对应的值 Set stringPropertyNames() 从该属性列表中返回一个不可修改的键集(键的集合),其中键及其对应的值是字符串
public static void main ( String [ ] args) {
Properties prop = new Properties ( ) ;
prop. setProperty ( "001" , "liubei" ) ;
prop. setProperty ( "002" , "guanyu" ) ;
prop. setProperty ( "003" , "zhangfei" ) ;
System . out. println ( prop) ;
System . out. println ( prop. getProperty ( "001" ) ) ;
System . out. println ( prop. getProperty ( "002" ) ) ;
System . out. println ( prop. getProperty ( "003" ) ) ;
Set < String > names = prop. stringPropertyNames ( ) ;
for ( String key : names) {
System . out. print ( key + "," ) ;
System . out. print ( prop. getProperty ( key) + " " ) ;
}
}
方法名 说明 void load(InpuStream inStream) 从输入字节流读取属性列表(键和元素对即键值对) void load(Reader reader) 从输入字符流读取属性列表(键和元素对) void store(OutpuStream out, String comments) 将此属性列表(键和元素对)写入此Properties表中,以适合于使用load(InputStream)方法的格式写入输出字节流 void store(Writer writer, String comments) ……适合于使用load(Reader)方法的格式写入输出字符流
public static void main ( String [ ] args) throws IOException {
myStore ( ) ;
myLoad ( ) ;
}
private static void myLoad ( ) throws IOException {
Properties prop = new Properties ( ) ;
FileReader fr = new FileReader ( "Copy.java" ) ;
prop. load ( fr) ;
fr. close ( ) ;
System . out. println ( prop) ;
}
private static void myStore ( ) throws IOException {
Properties prop = new Properties ( ) ;
prop. setProperty ( "001" , "liubei" ) ;
prop. setProperty ( "002" , "guanyu" ) ;
prop. setProperty ( "003" , "zhanfe" ) ;
FileWriter fw = new FileWriter ( "Copy.java" ) ;
prop. store ( fw, null ) ;
fw. close ( ) ;
}
案例:游戏次数
需求:请写程序实现猜数字小游戏只能试玩3次,如果还想玩,提示:游戏试玩已结束,想玩请充值(www.itcast.cn)。 思路: (1)写一个游戏类,里面有一个猜数字的小游戏; (2)写一个测试类,测试类中有main(),main()方法中按照下面步骤完成: A:从game.txt文件中读取数据到Properties集合,用load()实现。game.txt文件已存在且里面有一个数据值count=0; B:通过Properties集合获取到玩游戏的次数; C:判断次数是否到达了三次。如果到了,给出“游戏试玩已结束,想玩请充值(www.itcast.cn)”的提示;如果没到。玩游戏,count++,重新写回文件,用Properties的store()实现。
public class GuessNumber {
private GuessNumber ( ) { } ;
public static void start ( ) {
Random r = new Random ( ) ;
int number = r. nextInt ( 10 ) + 1 ;
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 ;
}
}
}
}
public static void main ( String [ ] args) throws IOException {
int count = 0 ;
while ( true ) {
Properties prop = new Properties ( ) ;
FileReader fr = new FileReader ( "game.txt" ) ;
prop. load ( fr) ;
fr. close ( ) ;
count = Integer . parseInt ( prop. getProperty ( "count" ) ) ;
if ( count>= 3 ) {
System . out. println ( "游戏试玩已结束,请充值!" ) ;
System . out. println ( "(www.itcast.cn)" ) ;
break ;
} else {
GuessNumber . start ( ) ;
count++ ;
prop. put ( "count" , String . valueOf ( count) ) ;
FileWriter fw = new FileWriter ( "game.txt" ) ;
prop. store ( fw, null ) ;
fw. close ( ) ;
}
}
}