Java 追加到ObjectOutputStream
是否无法附加到Java 追加到ObjectOutputStream,java,serialization,append,objectoutputstream,objectinputstream,Java,Serialization,Append,Objectoutputstream,Objectinputstream,是否无法附加到对象输出流 我试图附加到对象列表中。下面的代码段是一个在作业完成时调用的函数 FileOutputStream fos = new FileOutputStream (preferences.getAppDataLocation() + "history" , true); ObjectOutputStream out = new ObjectOutputStream(fos); out.writeObject( new Stuff(stuff) ); ou
对象输出流
我试图附加到对象列表中。下面的代码段是一个在作业完成时调用的函数
FileOutputStream fos = new FileOutputStream
(preferences.getAppDataLocation() + "history" , true);
ObjectOutputStream out = new ObjectOutputStream(fos);
out.writeObject( new Stuff(stuff) );
out.close();
但是当我试图阅读它时,我只得到文件中的第一个。
然后我得到java.io.StreamCorruptedException
阅读我正在使用的
FileInputStream fis = new FileInputStream
( preferences.getAppDataLocation() + "history");
ObjectInputStream in = new ObjectInputStream(fis);
try{
while(true)
history.add((Stuff) in.readObject());
}catch( Exception e ) {
System.out.println( e.toString() );
}
我不知道会有多少物体出现,所以我在阅读时没有例外。根据谷歌的说法,这是不可能的。我想知道是否有人知道一种方法?由于序列化文件的精确格式,追加确实会损坏它。您必须将所有对象作为同一个流的一部分写入文件,否则当它需要对象时,当它读取流元数据时,它将崩溃
您可以阅读更多详细信息,或者(更容易)阅读Roedy Green所说的基本内容。由于序列化文件的精确格式,附加内容确实会损坏它。您必须将所有对象作为同一个流的一部分写入文件,否则当它需要对象时,当它读取流元数据时,它将崩溃 您可以阅读以了解更多详细信息,或者(更容易)阅读Roedy Green所说的基本内容。如所述,
ObjectOutputStream
构造函数将序列化流头写入底层流。这个头应该只在文件开头出现一次。这么叫
new ObjectOutputStream(fos);
引用同一个文件的FileOutputStream
上多次写入头将多次写入并损坏文件。如所述,ObjectOutputStream
构造函数将序列化流头写入基础流。这个头应该只在文件开头出现一次。这么叫
new ObjectOutputStream(fos);
在引用同一文件的
文件OutputStream
上多次写入头会多次并损坏文件。避免此问题的最简单方法是在写入数据时保持OutputStream打开,而不是在每个对象之后关闭它。调用reset()
可以避免内存泄漏
另一种方法是将文件作为一系列连续的ObjectInputStreams读取。但这需要您计算读取的字节数(这可以通过FilterInputStream实现),然后关闭InputStream,再次打开它,跳过那么多字节,然后将其包装到ObjectInputStream()中。避免此问题的最简单方法是在写入数据时保持OutputStream打开,而不是在每个对象之后关闭它。调用
reset()
可以避免内存泄漏
另一种方法是将文件作为一系列连续的ObjectInputStreams读取。但这需要您计算读取的字节数(这可以通过FilterInputStream实现),然后关闭InputStream,再次打开它,跳过那么多字节,然后将其包装到ObjectInputStream()中。诀窍如下:子类
ObjectOutputStream
并重写writeStreamHeader
方法:
public class AppendingObjectOutputStream extends ObjectOutputStream {
public AppendingObjectOutputStream(OutputStream out) throws IOException {
super(out);
}
@Override
protected void writeStreamHeader() throws IOException {
// do not write a header, but reset:
// this line added after another question
// showed a problem with the original
reset();
}
}
要使用它,只需检查历史文件是否存在,并实例化此可追加流(如果文件存在=我们追加=我们不需要标头)或原始流(如果文件不存在=我们需要标头)
编辑
我对班级的第一个名字不满意。这个更好:它描述的是“它的用途”,而不是“它是如何完成的”
编辑
再次更改名称,以澄清此流仅用于附加到现有文件。它不能用于创建包含对象数据的新文件
编辑
添加了对
reset()
的调用,该调用显示,在某些情况下,将writeStreamHeader
重写为no-op的原始版本可能会创建一个无法读取的流。技巧如下:子类ObjectOutputStream
并重写writeStreamHeader
方法:
public class AppendingObjectOutputStream extends ObjectOutputStream {
public AppendingObjectOutputStream(OutputStream out) throws IOException {
super(out);
}
@Override
protected void writeStreamHeader() throws IOException {
// do not write a header, but reset:
// this line added after another question
// showed a problem with the original
reset();
}
}
要使用它,只需检查历史文件是否存在,并实例化此可追加流(如果文件存在=我们追加=我们不需要标头)或原始流(如果文件不存在=我们需要标头)
编辑
我对班级的第一个名字不满意。这个更好:它描述的是“它的用途”,而不是“它是如何完成的”
编辑
再次更改名称,以澄清此流仅用于附加到现有文件。它不能用于创建包含对象数据的新文件
编辑
添加了对
reset()
的调用,该调用显示,在某些情况下,将writeStreamHeader
重写为no-op的原始版本可能会创建无法读取的流。在每次追加对象之前,读取并复制文件中的所有当前数据,然后将所有数据一起覆盖到文件中 在每次附加对象之前,读取并复制文件中的所有当前数据,然后将所有数据一起覆盖到文件 我扩展了公认的解决方案,创建了一个类,可以用于追加和创建新文件
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
public class AppendableObjectOutputStream extends ObjectOutputStream {
private boolean append;
private boolean initialized;
private DataOutputStream dout;
protected AppendableObjectOutputStream(boolean append) throws IOException, SecurityException {
super();
this.append = append;
this.initialized = true;
}
public AppendableObjectOutputStream(OutputStream out, boolean append) throws IOException {
super(out);
this.append = append;
this.initialized = true;
this.dout = new DataOutputStream(out);
this.writeStreamHeader();
}
@Override
protected void writeStreamHeader() throws IOException {
if (!this.initialized || this.append) return;
if (dout != null) {
dout.writeShort(STREAM_MAGIC);
dout.writeShort(STREAM_VERSION);
}
}
}
此类可以用作ObjectOutputStream的直接扩展替换。
我们可以按如下方式使用该类:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class ObjectWriter {
public static void main(String[] args) {
File file = new File("file.dat");
boolean append = file.exists(); // if file exists then append, otherwise create new
try (
FileOutputStream fout = new FileOutputStream(file, append);
AppendableObjectOutputStream oout = new AppendableObjectOutputStream(fout, append);
) {
oout.writeObject(...); // replace "..." with serializable object to be written
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
我已经扩展了公认的解决方案,创建了一个可以用于追加和创建新文件的类
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
public class AppendableObjectOutputStream extends ObjectOutputStream {
private boolean append;
private boolean initialized;
private DataOutputStream dout;
protected AppendableObjectOutputStream(boolean append) throws IOException, SecurityException {
super();
this.append = append;
this.initialized = true;
}
public AppendableObjectOutputStream(OutputStream out, boolean append) throws IOException {
super(out);
this.append = append;
this.initialized = true;
this.dout = new DataOutputStream(out);
this.writeStreamHeader();
}
@Override
protected void writeStreamHeader() throws IOException {
if (!this.initialized || this.append) return;
if (dout != null) {
dout.writeShort(STREAM_MAGIC);
dout.writeShort(STREAM_VERSION);
}
}
}
此类可以用作ObjectOutputStream的直接扩展替换。
我们可以按如下方式使用该类:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class ObjectWriter {
public static void main(String[] args) {
File file = new File("file.dat");
boolean append = file.exists(); // if file exists then append, otherwise create new
try (
FileOutputStream fout = new FileOutputStream(file, append);
AppendableObjectOutputStream oout = new AppendableObjectOutputStream(fout, append);
) {
oout.writeObject(...); // replace "..." with serializable object to be written
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
您是否从流中获取了任何信息,或者它是否在循环的第一时间抛出异常?它读取我保存的第一个对象