这几天上班看了点 Java 的基础知识点,看到介绍序列化的基本问题是都是以介绍序列化对象和反序列化对象为例的,依此就想到了:要是壹次序列化多个对象,再或者不同时间多次序列化对象,应该怎么做,于是动手试了下,发现了不少问题,由于是小菜搞了好久上网找,才得以解决问题,废话不多说了,下面直接进入正题。
(壹)java序列化的基本原理知识:
http://yuyiming.iteye.com/blog/1277089
(二)壹次序列化多个对象及多次序列化产生的问题
对于壹次序列化多个对象的话,就是多次调用 writeObject() 方法就可以了。然而要注意的壹点就是在一次的序列化的过程中(写入文件到关闭文件的过程为一次序列化过程),ObjectOutputStream 对象写对象的话,会写入一个 header,也就是一次序列化的过程中会在文件开始的地方写入一个 Header 的信息到文件中,于此在多次序列化的过程中(如序列化一次关闭文件后,可能又需要往文件中序列化其他对象),此时就会继续在文件末尾(本次序列化的开头)写入 Header 的信息,如此如果进行反序列化的对象的时候会报如下错误:
java.io.StreamCorruptedException: invalid type code: AC
因为这是头的信息而不是对象的信息,为了解决这个办法,就必须在以后序列化的过程中不写入头文件即可,详细的解决办法见郑君华的博客:
多次ObjectOutputStream出现的错误。总结如下:
1、用同壹個 ObjectOutputStream 写对象;
2、但是大部分时候,要不断往某个文件记录对象,这样按照上面的说法就要维护壹個 ObjectOutputStream,然而重启应用时候就会重新创建壹個 ObjectOutputStream 对象,此时如果还是想往刚才那个文件里写对象的话,就会追加一个 header。这样在读对象时读到这个位置就会报错。解决方法是重写 ObjectOutputStream 类的 writeStreamHeader() 方法;
(三)多次反序列化多个对象时的解决方法
上面解决了多次序列化的问题,为此我们发现他们在反序列化对象的时候,必须要知道序列化了多少个对象,然后才能循环多少次把对象取出来,这样显然不是很方便,如果我文件和程序关闭了,我下次要是又想反序列化的时候,怎么才知道以前序列化了多少个对象呢?为此我们通过如下的方法来解决,因为在readObject()的时候,每次都是反序列化壹個对象,所以我们可以通过一个 while(true) 的循环来读取,当到文件最后的时候,会抛出EOFFileEnd的壹個异常,这样间接解决了判断结束的问题。代码如下:
public class SerializableTestListError {
private static List<Object> listObject = new ArrayList<Object>();
public static void main(String[] args) throws IOException {
Student stu1 = new Student(01044444441, "yteng1", 204);
Student stu2 = new Student(00444344441, "yteng2", 421);
Car car1 = new Car("DazsAut00144444444444400o", "ShangHai", 2000400.0);
Car car3 = new Car("DazsAuto114444444441", "ShangHai", 2000400.0);
Car car2 = new Car("For14444444d", "JiangSu", 300040.00);
listObject.add(car2);
listObject.add(car1);
listObject.add(car3);
listObject.add(stu1);
listObject.add(stu2);
writeObject2File(listObject, "D:\\new.txt");
try {
readObjectFromFile("D:\\new.txt");
} catch (SerializedException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void writeObject2File(List<Object> o, String fileName)
throws IOException {
File file = null;
FileOutputStream fos = null;
ObjectOutputStream oos = null;
try {
file = new File(fileName);
fos = new FileOutputStream(file, true);
if (file.length() < 1) {
oos = new ObjectOutputStream(fos);
} else {
oos = new MyObjectOutputStream(fos);
}
for (int i = 0; i < o.size(); i++)
oos.writeObject(o.get(i));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fos != null)
fos.close();
if (oos != null)
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void readObjectFromFile(String fileName) throws Exception {
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
fis = new FileInputStream(fileName);
ois = new ObjectInputStream(fis);
while (true)
System.out.println(ois.readObject());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
System.out.println("文件终止!~");
e.printStackTrace(); // 此处解决序列化完成后的异常
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
System.out.println("输出结束~");
} finally {
try {
if (fis != null)
fis.close();
if (ois != null)
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
这里我壹次序列化了多個对象,另外我们还可以用流机制反序列化多個对象。代码如下:
public class SerializableTest {
private static List<Student> listStudentObject = new ArrayList<Student>();
private static List<Car> listCarObject = new ArrayList<Car>();
private static List<Object> listObject = new ArrayList<Object>();
public static void main(String[] args) throws IOException {
Student stu1 = new Student(001, "yteng11", 20);
Student stu2 = new Student(002, "yteng22", 21);
Car car1 = new Car("DazsAuto", "ShangHai", 200000.0);
Car car2 = new Car("Ford", "JiangSu", 30000.00);
writeObject2File(stu1, "D:\\date.txt");
writeObject2File(stu2, "D:\\date.txt");
writeObject2File(car1, "D:\\date.txt");
writeObject2File(car2, "D:\\date.txt");
try {
readObjectFromFile("D:\\date.txt");
} catch (SerilizableException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
for (Iterator<Car> iterCar = listCarObject.iterator(); iterCar
.hasNext();) {
System.out.println(iterCar.next());
}
for (Iterator<Student> iterStudent = listStudentObject.iterator(); iterStudent
.hasNext();) {
System.out.println(iterStudent.next());
}
}
public static void writeObject2File(Object o, String fileName)
throws IOException {
FileOutputStream fout = new FileOutputStream(fileName, true);
ObjectOutputStream sout = new ObjectOutputStream(fout);
sout.writeObject(o);
sout.close();
System.out.println("写入对象成功!");
}
public static void readObjectFromFile(String fileName) throws Exception {
FileInputStream fin = new FileInputStream(fileName);
BufferedInputStream bis = new BufferedInputStream(fin);
ObjectInputStream oip = null;
while (true) {
try {
oip = new ObjectInputStream(bis); // 每次重新构造对象输入流
} catch (EOFException e) {
e.printStackTrace();
System.out.println("已达文件末尾");// 如果到达文件末尾,则退出循环
break;
}
Object object = new Object();
object = oip.readObject();
if (object instanceof Student) { // 判断对象类型
listStudentObject.add((Student) object);
} else if (object instanceof Car) {
listCarObject.add((Car) object);
}
}
oip.close();
bis.close();
fin.close();
}
}
本文中所有相关源代码见附件。