I/O流的学习(四)

序列化:将对象按照流的方式存储到文本文件中或者再网络中传输    对象---->流数据 序列化流 (ObjectOutputStream)

反序列化:将文本文件中的流对象或者网络传输中的流对象还原成对象   流数据--->对象  反序列化流(ObjectInputStream)

public class ObjectDemo {
	
	public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
		
//		write() ;
		read();
	}
	
	//反序列化
	private static void read() throws FileNotFoundException, IOException, ClassNotFoundException {
		
		//创建反序列化流对象
		//public ObjectInputStream(InputStream in)
		ObjectInputStream in = new ObjectInputStream(new FileInputStream("oos.txt")) ;
		
		//读
		//public final Object readObject():从 ObjectInputStream 读取对象。
		Object obj = in.readObject() ;
		
		in.close();
		System.out.println(obj);//Person [name=高圆圆, age=27]
	}

	
	//序列化
	private static void write() throws FileNotFoundException, IOException {
		
		//创建一个序列化流对象
		//public ObjectOutputStream(OutputStream out)
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("oos.txt")) ;
		
		//创建一个Person类对象
		Person p = new Person("高圆圆", 27) ;
		
		//public final void writeObject(Object obj)
		oos.writeObject(p);
		
		//关闭资源
		oos.close();
		
	}
}
java.io.NotSerializableException :当前类未实现序列化功能的异常

Serializable:接口 没有构造方法,没有字段,也没有方法
接口---->标记接口

自定义类要实现序列化功能,必须实现接口Serializable接口

类实现了serializable也意味着他是标记类

假设之前操作针对Peroson操作序列的时候,产生一个标记  Preson.class--->固定ID 100

name -100
age -100

已经序列化完毕了,然后又修改了Person类里面的一些东西,加入了toString()
Person.class---固定id -- 200

org.westos_01.Person; local class incompatible: 
stream classdesc serialVersionUID = -428218385429329797, 
local class serialVersionUID = -5865763454468005049
 
因为手动修改了这些类的属性/成员变量,将序列化版本Id改变了
InvalidClassException:一般情况:该类的序列版本号与从流中读取的类描述符的版本号不匹配 
实际开发中,不想多次对当前这些序列化,如果这样做,非常麻烦?
如何解决呢?
让当前实现类序列化功能的这个类产生一个固定ID,注意看程序有黄色警告线,直接就点它来固定Id

比如:当前的这个类中有很多属性(性别,地址,学号...),某些属性不想被序列化,如何解决这样一个问题

        transient int age  ;用transient来修饰这个类的属性,就不会被序列化

public class Person implements Serializable{
	
	//产生随机的固定Id
	private static final long serialVersionUID = 3929786557947102117L;

	private String name ;
//	private int age ;
//	public int age ;
	
	transient int age  ;//这样这个类的属性就不会被序列化
	
	public Person() {
		super();
	}
	
	public Person(String name, int age) {
		super();
		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 "Person [name=" + name + ", age=" + age + "]";
	}

}
Properties:表示了一个持久的属性集(简称:属性集合类)  extends Hashtable<K,V> Map集合的
可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。

public Properties():无参构造

public class PropertiesDemo {
	
	public static void main(String[] args) {
		
		//它继承Hashtable
		//创建一个属性集合类对象
		Properties prop = new Properties() ;
		System.out.println(prop);
		System.out.println("---------------------");
		
		//给属性集合类中的属性列表添加元素
		prop.put("高圆圆", "赵又廷") ;
		prop.put("文章", "马伊琍") ;
		prop.put("黄晓明", "baby") ;
		
		System.out.println(prop);
		
		//遍历属性集合类
		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) :给属性列表中添加键和值,并且强制都使用String
public Set<String> stringPropertyNames():遍历的功能

public String getProperty(String key)用指定的键在此属性列表中搜索属性

public class PropertiesDemo2 {
	
	public static void main(String[] args) {
		
		//创建属性集合类对象
		Properties prop = new Properties() ;
		
		//添加元素
		prop.setProperty("张三", "20") ;
		prop.setProperty("李四", "22") ;
		prop.setProperty("王五", "18") ;
		
		//遍历
		//获取所有的键的集合
		Set<String> keyset = prop.stringPropertyNames() ;
		for(String key:keyset) {
			//通过键找值
			String value = prop.getProperty(key) ;
			System.out.println(key+"----"+value);
		}
	}
}
可保存在流中或从流中加载,只能使用属性集合类
public void store(Writer writer,String comments):把集合中的数据保存文本文件中(属性集合)
public void load(Reader reader):将文本文件中的数据加载到属性集合中

举例:

打游戏:游戏进度的保存和游戏加载

public class PropertiesDemo3 {
	
	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("prop.txt") ;
		//加载
		prop.load(fr);
		fr.close();
		System.out.println(prop);
		
	}
	
	//将属性集合中的数据保存到文本文件中
	private static void MyStore() throws IOException {
		
		//创建一个属性集合类对象
		Properties prop = new Properties() ;
		
		//添加元素
		prop.setProperty("张三", "20") ;
		prop.setProperty("文章", "29") ;
		prop.setProperty("成龙", "55") ;
		
		//public void store(Writer writer,String comments):把集合中的数据保存文本文件中(属性集合)
		FileWriter fw = new FileWriter("name.txt") ;
		//将数据保存到文本文件中
		prop.store(fw, "names'content");
		
		//释放资源
		fw.close();
 		
	}
}
需求:我有一个文本文件(user.txt),我知道数据是键值对形式的,但是不知道内容是什么。请写一个程序判断是否有“lisi”这样的键存在,如果有就改变其实为”100
分析:  
      1)读取文件的内容,将文件内容加载属性集合类中
      2)遍历属性集合,获取所有的键的集合
      3)遍历的键的时候,可以判断是否有"lisi"这样一个键
      4)有的话,就更改

      5)需要将当前属性集合类中的保存文本文件中

public class PropertiesTest {
	
	public static void main(String[] args) throws IOException {
		
		//创建属性集合类对象
		Properties prop = new Properties() ;
		
		//读取文本文件内容加载到集合中
		FileReader fr = new FileReader("user.txt") ;
		prop.load(fr); 
		fr.close(); 
		
		//遍历属性集合
		//获取所有的键的集合
		Set<String> keySet = prop.stringPropertyNames() ;
		for(String key:keySet) {
			//判断
			if("lisi".equals(key)) {
				//更改
				prop.setProperty(key, "100") ;
			}
		}
		
		//将属性集合中的数据保存文本文件中
		FileWriter fw = new FileWriter("user.txt") ;
		prop.store(fw, "content");
		fw.close();

	}
}
需求:

我有一个猜数字小游戏的程序,请写一个程序实现在测试类中只能用5次,超过5次提示:游戏试玩已结束,请付费。

public class PropertiesTest2 {
	
	public static void main(String[] args) throws IOException {
		
		//创建文件
		/*File file = new File("content.txt") ;
		if(file!=null) {
			file.createNewFile() ;
		}*/
		
		//将文件的内容加载到属性集合中
		Properties prop = new Properties() ;
		//创建字符输入流
		FileReader fr = new FileReader("count.txt") ;
		prop.load(fr);
		fr.close();
		
		//现在有内容了,通过键获取当前对应的值(String)
		String value = prop.getProperty("count") ;
		
		//String--->int
		int number = Integer.parseInt(value) ;
		//判断
		//超过5次提示:游戏试玩已结束,请付费。
		if(number >5) {
			System.out.println("游戏试玩接收,请您付费...");
			System.exit(0);
		}else {
			number ++ ;
			prop.setProperty("count", String.valueOf(number)) ;
			FileWriter fw = new FileWriter("count.txt") ;
			prop.store(fw, "game'content");
			fw.close() ;
			
			GetNumber.start();
			
		}
	}
}
public class GetNumber {
	
	private GetNumber() {
		
	}
	
	//为了防止打断点的时候,黄色警告线会影响断点,所有加入强制解决
	@SuppressWarnings("resource")
	public static void start() {
		//1-100随机数
		int number = (int) (Math.random()*100+1) ;
		
		//定义一个统计变量
		int count = 0 ;
		
		while(true) {

			Scanner sc = new Scanner(System.in) ;
			System.out.println("请输入要猜的数据:");
			int guessNumber = sc.nextInt() ;
			
			count ++ ;
			if(guessNumber>number) {
				System.out.println("你要猜的数据大了...");
			}else if(guessNumber <number) {
				System.out.println("你要猜的数据小了...");
			}else {
				System.out.println("恭喜您"+count+"次猜中了...");
				break ;
			}
			
		}
	}
}


猜你喜欢

转载自blog.csdn.net/cangerwjd/article/details/80407574