`

自定义ObjectOutputStream,解决追加写入后,读取错误的问题

    博客分类:
  • J2SE
阅读更多
问题情景:

问题描述: 用类ObjectOutputStream向文件写读对象时,碰到一个问题:新建一个文
  件,用输出流ObjectOutputStream向文件连续写几个对象,关闭输出流,然
  后读取,这些对象都可以读出;这时在向该文件增加对象,新写的对象就读不出了,不知什么原因?请教了!
 
  问题出现的原因:ObjectOutputStream建立后第一次写入一个对象时, 会在对象数据前写入一些标志的数据“AC ED
  00 05”(用ultraEdit打开),应该是流相关的信息。当你关闭
  ObjectOutputStream后再重新打开往文件里面写对象时(append方式),就会再一次把“AC ED 00
  05”写入文件,而这些信息并不是你写入对象的数据,所以当你用ObjectInputStream来读取对象时,流会将除第一个“AC ED 00
  05”以外的数据当作各个对象的数据,造成无法解析,所以读取时有一个java.io.StreamCorruptedException出现。
  这个可以通过编辑Info.dat来验证,只要将“AC ED 00 05”删除(第一个“AC ED 00 05”保留)就可以正常读出后来加入的对象。
  给出一个比较笨的解决方法: 在以后要添加新的对象到Info.dat时,将里面原有的对象读出放入ArrayList中,清空文件,再将对象集一次写入。
 
  尝试解决办法: 那个“AC ED 00 05”是
  ObjectOutputStream.writeSystemHeader()写进去的,你可以继承ObjectOutputStream类,覆盖这个方法。
  在你自己的writeSystemHeader()里判断是不是第一次写入一个文件,如果是向一个文件大小不为零的文件追加的话,就调用
  super.reset(),如果是第一次写这个文件,不是追加,就调用super.writeSystemHeader()

自定义类MyObjectOutputStream
public class MyObjectOutputStream extends ObjectOutputStream {
	//定义成静态的好处
	private static File f;

	/**
	 * 初始化静态文件对象,并返回类对象
	 * @param file 文件对象,用于初始化静态文件对象
	 * @param out 输出流
	 * @return MyObjectOutputStream
	 * @throws IOException
	 */
	public static  MyObjectOutputStream newInstance(File file, OutputStream out)
			throws IOException {
		f = file;//本方法最重要的地方:构建文件对象,是两个文件对象属于同一个
		return new MyObjectOutputStream(out, f);
	}

	@Override
	protected void writeStreamHeader() throws IOException {
		if (!f.exists() || (f.exists() && f.length() == 0)) {
			super.writeStreamHeader();
		} else {
			super.reset();
		}

	}

	public MyObjectOutputStream(OutputStream out, File f) throws IOException {
		super(out);
	}

}


测试方法:
public static void writeObject() throws Exception {
		String filename = "test.txt";
		File f = new File(filename);
		OutputStream os = new FileOutputStream(f, true);
		MyObjectOutputStream moos = MyObjectOutputStream.newInstance(f, os);
		moos.writeObject("abc");
		moos.writeObject(1);
		moos.close();
	}
分享到:
评论
4 楼 Touch_2011 2011-10-21  
楼主讲的真精辟,thank you,学习了
3 楼 mckelvin 2011-03-15  
楼主帮了大忙!十分感谢!
2 楼 jqwu_csu 2010-09-16  
gmizr 写道
将f设为static,多线程使用的时候会出问题啊
writeStreamHeader是在构造函数被调用的,这个问题还真有点麻烦


恩,是的。 当构造多个MyObjectOutputStream 对象时,static file 会出问题,
是否可以用如下解决。


public class AppendObjectOutputStream extends ObjectOutputStream
{

private File file = null;

public AppendObjectOutputStream(File file) throws IOException
{
super(new FileOutputStream(file));
this.file = file;
}


public void writeStreamHeader() throws IOException
{
if(file != null)
{
if(file.length() == 0)
{
super.writeStreamHeader();
}
else
{
super.reset();
}
}
else
{
super.writeStreamHeader();
}

}
}
1 楼 gmizr 2009-07-01  
将f设为static,多线程使用的时候会出问题啊
writeStreamHeader是在构造函数被调用的,这个问题还真有点麻烦

相关推荐

    socket objectoutputstream 传对象 例子

    在Java编程中,Socket和ObjectOutputStream是两个非常重要的概念,它们是进行网络通信的基础。Socket是TCP/IP协议的实现,提供了两台计算机之间双向、独立的数据传输通道。而ObjectOutputStream则是一个序列化流,...

    对象的写入与读取。将一个类的对象(例如:Calendar)写入到文件,然后顺序读出该对象,并验证读出的对象是否原始对象的克隆。

    `ObjectOutputStream`可以将Java对象写入到字节流中,而`ObjectInputStream`则可以从字节流中恢复对象。 4. **数据流和对象流**:数据流(如`DataOutputStream`和`DataInputStream`)通常用于处理基本数据类型,而...

    Java保存与读取文件.rar

    Java保存与读取文件代码示例,super("存储与读取对象"); //调用父类构造函数  Container container=getContentPane(); //得到容器  Icon imageIcon=new ImageIcon("image.gif"); //实例化一个图标  ...

    Java将数据存储在obj文件中并读取出来.rar

    通过实现`Serializable`接口并使用`ObjectOutputStream`和`ObjectInputStream`,我们可以轻松地将数据存储到`.obj`文件中并在需要时读取出来。这对于数据持久化、跨进程通信和网络传输等场景非常有用。

    写入到文件,然后顺序读出该对象,并验证读出的对象

    在Java中,我们可以使用ObjectOutputStream类来实现对象的序列化,即将对象转换为字节流并写入到文件。序列化是将一个对象的状态(即它的属性)保存到持久存储设备(如磁盘)上的过程。这通常用于持久化数据或者在...

    封装保存和读取数据对象的工具类

    在实际开发中,这样的工具类还需要考虑到错误处理和安全性问题,例如文件不存在、权限不足或数据格式不正确等情况。同时,为了提高效率,可能还会采用缓存策略,避免频繁的磁盘操作。 总的来说,"封装保存和读取...

    Java存储与读取对象.rar

    序列化的关键类包括`ObjectOutputStream`用于写入对象到流中,以及`ObjectInputStream`用于从流中读取对象。例如: ```java import java.io.*; class MySerializable implements Serializable { // class ...

    mina自定义编码器-自行做会话累积

    然后,我们可以使用特定的序列化技术(如Java的`ObjectOutputStream`,或者自定义的序列化协议)将合并后的消息转换为字节流。 例如,我们可能创建一个`Message`类来存储要发送的数据,并在`IoSession`中维护一个...

    python-javaobj:python-javaobj是一个python库,提供了读取Java对象序列化ObjectOutputStream的函数

    python-javaobj 是一个 python 库,它提供了读取和写入(写入当前是 WIP)Java 对象的函数,序列化或将被ObjectOutputStream反序列化。 这种对象表示形式是 Java 世界中的标准数据交换格式。 javaobj 模块公开了...

    Java存储与读取对象.7z

    - **使用ObjectOutputStream**:要将对象写入到文件,可以使用`ObjectOutputStream`。它提供了`writeObject()`方法,用于将对象转换为字节流并写入到输出流。 - **使用ObjectInputStream**:读取序列化的对象时,...

    基于Java的源码-存储与读取对象.zip

    `ObjectOutputStream`用于写入对象到输出流,而`ObjectInputStream`则用于从输入流读取对象。 ```java try (FileOutputStream fos = new FileOutputStream("object.ser"); ObjectOutputStream oos = new ...

    把对象写到文件夹里边

    总结一下,Java中将对象写入文件涉及到的关键点包括:实现`Serializable`接口、使用`ObjectOutputStream`序列化对象并写入文件、使用`ObjectInputStream`反序列化并读取对象。了解和熟练掌握这些知识点对于进行数据...

    JAVA实验报告 读取服务器端的窗口

    8. **异常处理**:实验代码中包含了异常处理结构,如当服务器断开连接或出现其他问题时,会捕获并打印错误信息。 这个实验旨在帮助学生理解网络编程的基本概念,特别是如何通过套接字在客户端和服务器之间交换复杂...

    Java存储与读取对象源码

    在Java编程中,存储和读取对象是常见的需求,特别是在持久化数据或者跨程序传递对象时。本主题将深入探讨如何在Java中实现这一功能,主要涉及对象序列化和反序列化的过程。 对象序列化是将Java对象转换为字节流的...

    创建文件并写入后显示在控制台

    在这个场景中,"创建文件并写入后显示在控制台"指的是利用序列化技术将对象写入文件,并能够通过读取文件在控制台查看这些数据。 首先,我们来看`WriteAReadSerializ.java`,这可能是一个包含序列化和反序列化操作...

    Java中对于字节流的读取方式

    例如,使用FileInputStream可以从文件中读取字节,而FileOutputStream则用于向文件写入字节。 ```java FileInputStream fis = new FileInputStream("input.txt"); byte[] buffer = new byte[1024]; int bytesRead; ...

    java序列化对象的存储和读取共6页.pdf.zip

    - 如果类的结构(如字段或方法)在序列化后发生变化,可能需要处理版本兼容性问题。 - 序列化可能会占用大量内存,特别是在序列化大量对象时。 7. **优化序列化:** - 使用`writeReplace()`和`readResolve()`...

    Java语言细节问题大全.rar

    `Serializable`接口标记一个类可以被序列化,`ObjectOutputStream`用于写入对象,`ObjectInputStream`用于读取。序列化还涉及到版本控制和反序列化安全问题。 5. 网络编程: `java.net`包提供了网络编程的基本功能...

    Java序列化多次追加到txt以及从txt反序列化

    Java序列化是Java平台提供的一种...通过使用`ObjectOutputStream`和`ObjectInputStream`,我们可以方便地将对象写入和读取文件,尤其是在需要追加多个对象到同一个文件时。同时,确保处理好异常,以确保程序的健壮性。

Global site tag (gtag.js) - Google Analytics