JavaIO流四
IO流四
一、对象序列化流与对象反序列化流
1.1、什么是序列化?什么是反序列化
对象序列化:就是将对象保存在磁盘中,或者在网络中传输对象
这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的类型、对象的数据和对象中存储的属性等信息字节序列写到文件之后,相当于文件中持久保存了一个对象的信息
反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化
要实现对象序列化和反序列化就要使用对象序列化流和对象反序列化流:
- 对象序列化流:ObjectOutputStream
- 对象反序列化流:ObjectInputStream
1.2、对象序列化流
对象序列化流:ObjectOutputStream
- ObjectOutputStream将Java对象的原始数据类型和图形写入OutputStream。 可以使用ObjectInputStream读取(重构)对象。 可以通过使用流的文件来实现对象的持久存储。 如果流是网络套接字流,则可以在另一个主机上或另一个进程中重构对象。
构造方法:
- ObjectOutputStream(OutputStream out):创建一个写入指定的OutputStream的ObjectOutputStream。
序列化对象的方法:
- void writeObject(Object obj):将指定的对象写入ObjectOutputStream
注意:
- 一个对象要想被序列化,该对象所属的类必须实现Serializable接口;
- Serializable是一个标记接口,实现该接口,不需要重写任何方法。
public class ObjectOutputStreamdemo {
public static void main(String[] args) throws IOException {
//ObjectOutputStream(OutputStream out):创建一个写入指定的OutputStream的ObjectOutputStream。
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Java基础语法\\oos.txt"));
//创建学生类以及学生对象
Student s1 = new Student("李明",18);
oos.writeObject(s1);
//NotSerializableException:抛出一个实例需要一个Serializable接口。序列化运行时或实例的类可能会抛出此异常。
//Serializable:类的序列化由实现java.io.Serializable接口的类启用。不实现此接口的类将不会使任何状态序列化或反序列化。
oos.close();
}
}
1.3、对象反序列化流
对象反序列化流: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("Java基础语法\\oos.txt"));
//Object readObject():从ObjectInputStream读取一个对象。
Object obj = ois.readObject();
Student s = (Student)obj;
System.out.println(s);
ois.close();
}
}
1.4、SerialVersionUID&&Transient
/*问题一、对象序列化流序列化一个对象后,假如我们修改了对象所属的类文件,读取数据会不会出问题呢?
答:会出问题,抛出InvalidClassException:当序列化运行时检测到类中的以下问题之一时抛出:
类的串行版本与从流中读取的类描述符的类型不匹配 ;
该类包含未知的数据类型 ;
该类没有可访问的无参数构造函数 ;
* 问题二、如果出问题了如何解决?
答:给这个对象所属的类文件加一个值:private static final long serialVersionUID = 42L;
* 问题三、如果一个对象中某个成员变量的值不想被序列化,又该如何实现?
答:可以给所对应得成员变量添加一个关键字:transient;例如:private transient int age
*/
import java.io.*;
public class ObjectStreamdemo {
public static void main(String[] args) throws IOException,ClassNotFoundException{
// writer();
read();
}
//反序列化
private static void read() throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Java基础语法\\oos.txt"));
Object obj = ois.readObject();
Student s = (Student)obj;
System.out.println(s.getName()+","+s.getAge());
ois.close();
}
//序列化
private static void writer() throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Java基础语法\\oos.txt"));
Student s1 = new Student("李明",18);
oos.writeObject(s1);
oos.close();
}
}
二、Properties
2.1、properties的基本概述
- 是Map体系的集合类
Properties
可以保存到流中或从流中加载
2.2、Properties作为Map集合的使用
public class PropertiesDemo01 {
public static void main(String[] args) {
//创建Properties对象
// Properties<String,String> prop = new Properties<String,String>();//错误写法,不能写泛型类
Properties prop = new Properties();
//存储元素
prop.put("demo001","李明");
prop.put("demo002","吴华");
prop.put("demo003","王芳");
//遍历集合
Set<Object> keyset = prop.keySet();
for (Object key:keyset){
Object value = prop.get(key);
System.out.println(key+","+value);
}
}
}
2.3、Properties作为Map集合的特有方法
- Object
setProperty(String key, String value)
:设置集合的键和值,都是String类型;底层调用Hashtable方法 put - String getProperty(String key): 使用此属性列表中指定的键搜索属性。
Set<String>
stringPropertyNames(): 返回此属性列表中的一组键,其中键及其对应的值为字符串
public class PropertiesDemo02 {
public static void main(String[] args) {
//创建集合对象
Properties prop = new Properties();
prop.setProperty("demo001","李昊");
prop.setProperty("demo002","王浩");
prop.setProperty("demo003","张丹");
System.out.println(prop);//{demo002=王浩, demo001=李昊, demo003=张丹}
System.out.println(prop.getProperty("demo002"));//王浩
System.out.println(prop.getProperty("demo004"));//null
Set<String> names = prop.stringPropertyNames();
for (String key:names){
// System.out.println(key);//结果为这些键的集合
String value = prop.getProperty(key);
// System.out.println(value);//结果为键对应的值
System.out.println(key+","+value);//结果为键和值
}
}
}
2.4、Properties和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)方法的写入输出字符流
//Properties和IO流中的字节流结合使用
public class PropertiesDemo03 {
public static void main(String[] args) throws IOException{
//把集合中的数据保存到文件
// mystore();
//把文件中的数据加载到集合
myLoad();
}
private static void myLoad() throws IOException{
Properties prop = new Properties();
FileInputStream fis = new FileInputStream("Java基础语法\\fos.txt");
prop.load(fis);
fis.close();
System.out.println(prop);
}
private static void mystore() throws IOException {
Properties prop = new Properties();
prop.setProperty("001","wang");
prop.setProperty("002","li");
prop.setProperty("003","zhang");
FileOutputStream fos = new FileOutputStream("Java基础语法\\fos.txt");
prop.store(fos,null);
fos.close();
}
}
//Properties和IO流中的字符流结合使用
public class PropertiesDemo04 {
public static void main(String[] args) throws IOException {
//把集合中的数据保存到文件
// mystore();
//把文件中的数据加载到集合
myLoad();
}
private static void myLoad() throws IOException {
Properties prop = new Properties();
FileReader fr = new FileReader("Java基础语法\\fw.txt");
prop.load(fr);
fr.close();
System.out.println(prop);
}
private static void mystore() throws IOException {
Properties prop = new Properties();
prop.setProperty("001","王芳");
prop.setProperty("002","李东");
prop.setProperty("003","林动");
FileWriter fw = new FileWriter("Java基础语法\\fw.txt");
prop.store(fw,null);
fw.close();
}
}
2.5、案例
//需求:用程序实现猜数字小游戏只能试玩3次,如果想要继续玩,提示:游戏试玩已结束,想玩请充值(www.itcat.cn)
//1、编写游戏类,实现猜数字游戏
//2、写一个测试类
public class GuessNumberTest {
public static void main(String[] args) throws IOException {
//properties集合读取文件中的数据,用load()实现
Properties prop = new Properties();
FileReader fr = new FileReader("Java基础语法\\game.txt");
prop.load(fr);
fr.close();
//通过properties集合方法获取到其中玩的次数
String cout = prop.getProperty("cout");
//把cout的String类型转化为Int类型
int number = Integer.parseInt(cout);
//判断是否到三次了
if (number>=3){
//如果到了,给出提示:游戏试玩已结束,想玩请充值(www.itcat.cn)
System.out.println("游戏试玩已结束,想玩请充值(www.itcat.cn)");
}else {
//不到,继续游戏
GuessNumer.start();
//次数加1,重新写回文件,用store()实现
number++;
prop.setProperty("cout", String.valueOf(number));
FileWriter fw = new FileWriter("Java基础语法\\game.txt");
prop.store(fw,null);
fw.close();
}
}
}
//------------------------------------------------------------------------------------
//猜数字小游戏实现
public class GuessNumer {
public GuessNumer() {
}
public static void start(){
//猜数字之前,肯定需要有一个需要被猜的数字,给出一个随机数,范围是1~100
Random r = new Random();
int ordernumber = r.nextInt(100)+1;
while(true){//如果产生的数字合法
//控制输入一个所猜的数
Scanner sc = new Scanner(System.in);
System.out.println("请输入你猜的数:");
int guessnumber = sc.nextInt();
//对目标数和所猜数进行判断
if (guessnumber>ordernumber){
System.out.println("你猜的数字"+guessnumber+"大了");
}else if(guessnumber<ordernumber){
System.out.println("你猜的数字"+guessnumber+"小了");
}else {
System.out.println("恭喜你猜对了!");
break;
}
}
}
}