Zydecx's Site

Debug code, debug life, debug today!

ObjectOutputStream追加写入导致读取报错的问题分析

Time: , by zydecx

问题现象:使用ObjectOutputStream向同一个文件写入多个对象,
A). 当ObjectOutputStream在打开后连续写入多个对象再关闭,可通过ObjectInputStream正常读取写入的多个对象;
B). 当每写入一个对象即关闭ObjectOutputStream并在写入下一个对象时重新打开,通过ObjectInputStream读取对象时,可以正常读取第一个对象,但读取第二个对象时报错。典型的报错信息如下:

Exception in thread "main" java.io.StreamCorruptedException: invalid type code: AC
	at java.io.ObjectInputStream.readObject0(Unknown Source)
	at java.io.ObjectInputStream.readObject(Unknown Source)
	at com.demo.ObjectSerializationDemo.writeObjectsSeparately(ObjectSerializationDemo.java:69)
	at com.demo.ObjectSerializationDemo.main(ObjectSerializationDemo.java:17)
		

问题原因:创建ObjectOutputStream对象时,会向输出流中写入标志数据“AC ED 00 05”;创建ObjectInputStream对象时,会自动解析输入流中开始的这些标志数据,因此采用方法A操作可以正常读取写入的对象。

但当采用方法B)时,由于ObjectOutputStream创建了两次,因此写入第二个对象时,会再次添加标志数据;ObjectInputStream仅能解析第一个对象前的标志数据,后面的标志数据当作对象数据处理,导致处理错误。

可参考这篇文章的内容。

方法A)示例程序:

public static void writeObjectsContinually() throws FileNotFoundException, IOException, ClassNotFoundException  {
	System.out.println("Write 2 Objects in one ObjectOutputStream:");
	
	String[] array1 = {"this", "is", "a", "demo", "program"};
	String[] array2 = {"this", "is", "also", "a", "demo", "program"}; 
	File f1 = new File("object.out_1");
	File f2 = new File("object.out_2");
		
	/**
	 * 在一个OutputStream中写入array1和array2
	 */
	ObjectOutputStream outputStream;
	outputStream = new ObjectOutputStream(new FileOutputStream(f1));
	outputStream.writeObject(array1);
	outputStream.writeObject(array2);
	outputStream.flush();
	outputStream.close();

	/**
	 * 读取array1和array2
	 */
	ObjectInputStream inputStream;
	inputStream = new ObjectInputStream(new FileInputStream(f1));
	String[] arrayOut1 = (String[]) inputStream.readObject();
	String[] arrayOut2 = (String[]) inputStream.readObject();
	inputStream.close();

	System.out.printf("==>>%s\n==>>before:%s\n==>>after:%s\n", "array1", Arrays.toString(array1), Arrays.toString(arrayOut1));
	System.out.printf("==>>%s\n==>>before:%s\n==>>after:%s\n", "array2", Arrays.toString(array2), Arrays.toString(arrayOut2));
}
		

方法B)示例程序:

public static void writeObjectsSeparately() throws FileNotFoundException, IOException, ClassNotFoundException  {
	System.out.println("Write 2 Objects in two ObjectOutputStreams:");
	
	String[] array1 = {"this", "is", "a", "demo", "program"};
	String[] array2 = {"this", "is", "also", "a", "demo", "program"}; 
	File f1 = new File("object.out_1");
	File f2 = new File("object.out_2");
	
	ObjectOutputStream outputStream;
	/**
	 * 打开OutputStream,写入array1
	 */
	outputStream = new ObjectOutputStream(new FileOutputStream(f2, true));
	outputStream.writeObject(array1);
	outputStream.flush();
	outputStream.close();
	/**
	 * 打开OutputStream,写入array2
	 */
	outputStream = new ObjectOutputStream(new FileOutputStream(f2, true));
	outputStream.writeObject(array2);
	outputStream.flush();
	outputStream.close();
	
	/**
	 * 读取array1和array2
	 */
	ObjectInputStream inputStream;
	inputStream = new ObjectInputStream(new FileInputStream(f2));
	String[] arrayOut11 = (String[]) inputStream.readObject();	// 第一个对象读取成功
	String[] arrayOut22 = (String[]) inputStream.readObject();	// 第二个对象读取时抛出异常
	inputStream.close();

	System.out.printf("==>>%s\n==>>before:%s\n==>>after:%s\n", "array1", Arrays.toString(array1), Arrays.toString(arrayOut11));
	System.out.printf("==>>%s\n==>>before:%s\n==>>after:%s\n", "array2", Arrays.toString(array2), Arrays.toString(arrayOut22));
}
		


This is a magic phrase. You CANNOT see it(I'll really FULE you if you do that), but it does work. Why? You may feel confused. OK, at least it doesn't afftect your experience and it works. That is what we call MAGICE!