现在的位置: 首页 > 综合 > 正文

Java 序列化和反序列化工具类并解决StreamCorruptedException问题

2018年06月05日 ⁄ 综合 ⁄ 共 4842字 ⁄ 字号 评论关闭

问题:

若通过ObjectOutputStream向一个文件中多次以追加的方式写入Object,为什么用ObjectInputStream读取这些Object时,会产生StreamCorruptedException

原因:

使用缺省的serializetion的实现时,一个ObjectOutputStream的构造和一个ObjectInputStream的构造必须一一对应,ObjectOutputStream的构造函数会向输出流中写入一个标识头,而ObjectInputStream会首先读入这个标志头,因此,多次以追加方式向一个文件写入Object时,该文件将会包含多个标志头,所以用ObjectInputStream来deserialize这个ObjectOutputStream时,将产生StreamCorruptedException。

解决方案:

构造一个ObjectOutputStream的子类,并覆盖writeStreamHeader()方法,被覆盖后的writeStreamHeader()方法应判断是否为首次向文件中写入Object,是则调用super.writeStreamHeader();若否,即以追加方式写入Object时,则应调用ObjectOutputStream.reset()方法。

案例:

创建测试类,在控制台上显示添加学生信息,要求程序循环运行,并依次提示接收学生类的所有属性值,保存到学生对象中,再将学生对象保存到集合对象中,并提示“是否继续添加(y/n):”,如果选择“y”则继续添加,否则退出循环,并将保存学生数据的集合对象通过序列化保存到“student.dat”文件中。然后实现从“student.dat”文件中反序列化保存学生数据的集合对象,并遍历打印输出学生信息。

解决StreamCorruptedException的错误:

/**
 * 这个类可以避免StreamCorruptedException
 * @author Liao
 *
 */
public class MyObjectOutputStream extends ObjectOutputStream {

	//无参构造函数
	public MyObjectOutputStream() throws IOException, SecurityException {
		super();
	}
	//有参构造函数
	public MyObjectOutputStream(OutputStream out) throws IOException {
		super(out);
	}
	
	/**
	 * 重写writeStreamHeader()方法
	 */
	@Override
	protected void writeStreamHeader() throws IOException {
		// TODO Auto-generated method stub
		return ;
	}

}

工具类:

public class SerializableUtil implements Serializable{

	private static final long serialVersionUID = 1L;

	/**
	 * 序列化对象
	 * 用户传一个Object类型对象,和要序列化到的文件路径即可进行序列化
	 * @param obj对象
	 * @param path 对象要被序列化到的文件路径
	 */
	public static void serializObject(Object obj,String path){
		
		//创建文件
		File file = new File(path);
		//判断文件是否存在
		if (!file.exists()){
			//如果文件不存在,就创建文件
			try {
				file.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		//创建ObjectOutputStream
		ObjectOutputStream objectOutputStream = null;
		
		try {
			//定义FileOutputStream,用于创建ObjectOutputStream
			OutputStream outputStream = new FileOutputStream(file, true);
			if (file.length() < 1){
				objectOutputStream = new ObjectOutputStream(outputStream);
			} else {
				objectOutputStream = new MyObjectOutputStream(outputStream);
			}
			//把对象序列化到文件中
			objectOutputStream.writeObject(obj);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {//强制关闭ObjectOutputStream
			try {
				objectOutputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		
	}
	
	/**
	 * 反序列化一个对象
	 * 
	 * @param path 要反序列的文件的路径
	 * @return 返回一个被反序列化的对象
	 */
	@SuppressWarnings("resource")
	public static Object unserializObject(String path){
		//定义一个对象
		Object obj = null;
		//创建一个文件
		File file = new File(path);
		
		try {
			//创建文件输入流
			InputStream inputStream = new FileInputStream(file);
			//通过文件输入流创建ObjectInputStream
			ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
			//获取一个对象
			obj = objectInputStream.readObject();
		} catch (Exception e) {
			
			e.printStackTrace();
		}
		
		//返回一个对象
		return obj;
	}
	
	/**
	 * 序列化一个集合
	 * 用户传一个集合和要序列化到的路径即可进行序列化
	 * @param collections 集合
	 * @param path 要序列化的路径
	 */
	public static <T>  void serializList(List<T> collections,String path){
		//创建文件
				File file = new File(path);
				//判断文件是否存在
				if (!file.exists()){
					//如果文件不存在,就创建文件
					try {
						file.createNewFile();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				//创建ObjectOutputStream
				ObjectOutputStream objectOutputStream = null;
				
				try {
					//定义FileOutputStream,用于创建ObjectOutputStream
					OutputStream outputStream = new FileOutputStream(file, true);
					if (file.length() < 1){
						objectOutputStream = new ObjectOutputStream(outputStream);
					} else {
						objectOutputStream = new MyObjectOutputStream(outputStream);
					}
					//遍历集合,然后把对象序列化到文件中
					for (T collection : collections){
						objectOutputStream.writeObject(collection);
					}
					
				} catch (Exception e) {
					e.printStackTrace();
				} finally {//强制关闭ObjectOutputStream
					try {
						objectOutputStream.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				
	}
	
	/**
	 * 反序列化一个List集合
	 * 因为文件中有多个对象,如何在反序列化到末尾时,终止反序列化呢?
	 * 这里有一个技巧,我们可以通过一个死循环,一直读知道抛出EOFException时就break退出循环
	 * @param path路径
	 * @return 返回一个集合
	 */
	@SuppressWarnings("unchecked")
	public static <T> List<T> unserializList(String path){
		//创建一个文件
		File file = new File(path);
		//创建一个List集合用于存储反序列化后的对象
		List<T> collections = new ArrayList<T>();
		//定义ObjectInputStream
		ObjectInputStream objectInputStream = null;
		try {
			//创建文件输入流
			InputStream inputStream = new FileInputStream(file);
			objectInputStream = new ObjectInputStream(inputStream);
			//获取一个对象
			while (true){
				try {
					//反序列化一个对象
					T t = (T) objectInputStream.readObject();
					//把该对象添加到集合中
					collections.add(t);
				} catch (EOFException e) {
					break;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				objectInputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		//返回一个对象
		return collections;
	}
	
}

测试类:

/**
 * 测试类
 * @author Liao
 *
 */
public class SerializationTest {

	public static void main(String[] args) {
		
		Scanner in = new Scanner(System.in);

		boolean flag = true;
		
		//创建集合用于存放实体对象
		List<Person> persons = new ArrayList<Person>();
		
		while (flag) {
			// 输入用户ID
			System.out.print("请输入UID:");
			Integer uid = in.nextInt();
			// 输入用户名
			System.out.print("请输入用户名:");
			String uname = in.next();
			// 输入性别
			System.out.print("请输入性别:");
			String gender = in.next();

			//把Person对象存到集合中
			persons.add(new Person(uid, uname, gender.equals("男")? Gender.MAN : Gender.WOMEN));
			
			// 是否继续
			System.out.print("是否继续? y/n:");

			String ifContinue = in.next();

			if (ifContinue.equals("n")) {
				flag = false;
			}
		}
		
		//序列化
		SerializableUtil.serializList(persons, "D:\\liaozhongmin.txt");
		
		//反序列化
		List<Person> collections = SerializableUtil.unserializList("D:\\liaozhongmin.txt");
		System.out.println(collections);
	}

}

抱歉!评论已关闭.