Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/402.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 追加到ObjectOutputStream_Java_Serialization_Append_Objectoutputstream_Objectinputstream - Fatal编程技术网

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();
        }

    }

}

您是否从流中获取了任何信息,或者它是否在循环的第一时间抛出异常?它读取我保存的第一个对象