遇到一个对象串行化问题,第一次正常串行化写入Date对象和反串行化对象没有错误,
第二次以追加的方式继续写入一个Date对象,然后在反串行化引发StreamCorruptedException异常
在google,baidu上找到了引发异常的原因,
ObjectOutputStream的构造函数会向输出流中写入一个标识头,而ObjectInputStream会首先读入这个标识头.
因此,多次以追加方式向一个文件中写入object时,该文件将会包含多个标识头.
所以用ObjectInputStream来deserialize这个 ObjectOutputStream时,将产生StreamCorruptedException.
一种解决方法是可以构造一个 ObjectOutputStream的子类,并覆盖writeStreamHeader()方法.
被覆盖后的writeStreamHeader()方法应判断是否为首次向文件中写入object,
否则调用super.writeStreamHeader();
若否,即以追加方式写入object时, 则应调用ObjectOutputStream.reset()方法.
引发原因想明白了,但是对于提供的解决方法没有弄明白,来CSDN学习学习如何读取追加的追加的方式写入对象和反串行化追加的对象。
问题1.如何对一个类的对象只写入一个头信息
2.ObjectOutputStream对象的reset()方法起什么作用,谁能够给形象的描述?
同样问题你解决方案
http://topic.csdn.net/u/20090408/14/d675c9ec-180f-4a24-8609-a32bc1402d9c.html#r_achor
问题虽然可以这么解决但是不感觉不是最佳方案,这个问题的关键是什么?在追加的时候重新写入对象的头文件?如何写入头文件,如何写呢?
源代码:
/虽然花费了我一个早上,但值啊
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashSet;
import java.util.Set;
/**
* 数据操作。保存、查询等。。。
*
* @author kreadk
*
*/
public class UserDao {
/**
* 文件路径
*/
private static final String FILE_PATH = "users.dat";
// public ObjectOutputStream outSteam;
public UserDao() {
}
public void saveUser1(User user) throws IOException {
ObjectOutputStream outSteam = null;
try {
// 带有true参数的FileOutputStream
outSteam = new ObjectOutputStream(new FileOutputStream(FILE_PATH,
true)) {
// 如是果要附加对象到文件后
// 必须重新定义这个方法
// 如果不是追加方式这样写后果自负啊
protected void writeStreamHeader() throws IOException {
}
};
outSteam.writeObject(user);
outSteam.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
outSteam.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void saveUser2(Set users) {
ObjectOutputStream outSteam = null;
try {
// ???
outSteam = new ObjectOutputStream(new FileOutputStream(FILE_PATH,
true)) {
// 如是果要附加对象到文件后
// 必须重新定义这个方法
// 如果不是追加方式这样写后果自负啊
protected void writeStreamHeader() throws IOException {
}
};
for (User user : users) {
outSteam.writeObject(user);
}
outSteam.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
outSteam.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 查询出所有用户
public void findAllUser() {
ObjectInputStream ois = null;
try {
FileInputStream tempSteam = new FileInputStream(FILE_PATH);
ois = new ObjectInputStream(tempSteam);
Object obj;
while (tempSteam.available() > 0) {// 你原来的这里可是死循环啊
obj = ois.readObject();
if (obj instanceof User) {// 建议加上这句
User user = (User) obj;
System.out.println(user);
}
}
} catch (EOFException e) {
//
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws Exception {
UserDao dao = new UserDao();
User u1 = new User("LILI", 19);
User u2 = new User("LUCY", 15);
User u3 = new User("HEHE", 17);
Set users = new HashSet();// Set users = new
// HashSet();换成前面的
/*****************假设我的机子上还没有FILE_PATH***********************************/
ObjectOutputStream outStream= new ObjectOutputStream(new FileOutputStream(FILE_PATH ));//无论是否存在再创建个
//写的这里有点不合适,你可以写在其他地方(最好事先判断一下文件是否存在,不存在再创建
/****************************************************/
// 下面这样写的前提必须是FILE_PATH必须存在(就是空文件也可以,只要他存在),要不会抛出invalid stream header
// ObjectOutputStream outSteam = new ObjectOutputStream(new FileOutputStream(FILE_PATH,true)) {
// // 如是果要附加对象到文件后
// // 必须重新定义这个方法
// // 如果不是追加方式这样写后果自负啊
// protected void writeStreamHeader() throws IOException {
// }
// };
users.add(u1);
users.add(u2);
users.add(u3);
System.out.println("方法1:----------------------------------");
dao.saveUser1(u1);
dao.saveUser1(u2);
dao.saveUser1(u3);
dao.findAllUser();
System.out.println("方法2:----------------------------------");
dao.saveUser2(users);
dao.findAllUser();
}
}
结果
方法1:----------------------------------
LILI , 19
LUCY , 15
HEHE , 17
方法2:----------------------------------
LILI , 19
LUCY , 15
HEHE , 17
LUCY , 15
LILI , 19
HEHE , 17