现在,当我尝试追加一个对象时,我会遇到java.io.StreamCorruptedException
的问题。我已经在互联网上搜索了解决方法。目前找到的答案是无法解决该问题。解决这个问题的一个方法是将对象写入列表中,然后再将列表写入文件。
但是,每次添加新对象时,我必须覆盖该文件。在长时间内,这似乎不是最优解。
是否有一种方法可以将对象追加到现有的对象流中?
现在,当我尝试追加一个对象时,我会遇到java.io.StreamCorruptedException
的问题。我已经在互联网上搜索了解决方法。目前找到的答案是无法解决该问题。解决这个问题的一个方法是将对象写入列表中,然后再将列表写入文件。
但是,每次添加新对象时,我必须覆盖该文件。在长时间内,这似乎不是最优解。
是否有一种方法可以将对象追加到现有的对象流中?
实际上这很容易做到。当您向现有流添加内容时,需要使用ObjectOutStream的子类来覆盖writeStreamHeader
方法,以便在文件中间不会写入第二个标头。例如:
class NoHeaderObjectOutputStream extends ObjectOutputStream {
public NoHeaderObjectOutputStream(OutputStream os) {
super(os);
}
protected void writeStreamHeader() {}
}
import java.io.*;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) throws Exception {
File storageFile = new File("test");
storageFile.delete();
write(storageFile, getO1());
write(storageFile, getO2());
write(storageFile, getO2());
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(storageFile));
read(ois, getO1());
read(ois, getO2());
read(ois, getO2());
}
private static void write(File storageFile, Map<String, String> o) throws IOException {
ObjectOutputStream oos = getOOS(storageFile);
oos.writeObject(o);
oos.close();
}
private static void read(ObjectInputStream ois, Map<String, String> expected) throws ClassNotFoundException, IOException {
Object actual = ois.readObject();
assertEquals(expected, actual);
}
private static void assertEquals(Object o1, Object o2) {
if (!o1.equals(o2)) {
throw new AssertionError("\n expected: " + o1 + "\n actual: " + o2);
}
}
private static Map<String, String> getO1() {
Map<String, String> nvps = new HashMap<String, String>();
nvps.put("timestamp", "1326382770000");
nvps.put("length", "246");
return nvps;
}
private static Map<String, String> getO2() {
Map<String, String> nvps = new HashMap<String, String>();
nvps.put("timestamp", "0");
nvps.put("length", "0");
return nvps;
}
private static ObjectOutputStream getOOS(File storageFile) throws IOException {
if (storageFile.exists()) {
// this is a workaround so that we can append objects to an existing file
return new AppendableObjectOutputStream(new FileOutputStream(storageFile, true));
} else {
return new ObjectOutputStream(new FileOutputStream(storageFile));
}
}
private static class AppendableObjectOutputStream extends ObjectOutputStream {
public AppendableObjectOutputStream(OutputStream out) throws IOException {
super(out);
}
@Override
protected void writeStreamHeader() throws IOException {
// do not write a header
}
}
}
正如文章所述,您可以使用以下解决方案之一:
Solution #1: Fake Multiple file in a Single Stream
...
Write your “transaction” to a ByteArrayOutputStream, then write the length and contents of this ByteArrayOutputStream to a file via the DataOutputStream.
Solution #2: Reopen and Skip
Another solution involves saving the file position using:
long pos = fis.getChannel().position();
closing the file, reopening the file, and skipping to this position before reading the next transaction.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
public class SerializationDemo {
public static void main(String[] args) throws Exception {
File storageFile = new File("test.ser");
storageFile.delete();
write(storageFile, getO1());
write(storageFile, getO2());
write(storageFile, getO2());
FileInputStream fis = new FileInputStream(storageFile);
read(fis, getO1());
read(fis, getO2());
read(fis, getO2());
fis.close();
}
private static void write(File storageFile, Map<String, String> o)
throws IOException {
ObjectOutputStream oos = getOOS(storageFile);
oos.writeObject(o);
oos.flush();
oos.close();
}
private static void read(FileInputStream fis, Map<String, String> expected)
throws ClassNotFoundException, IOException {
Object actual = getOIS(fis).readObject();
assertEquals(expected, actual);
System.out.println("read serialized " + actual);
}
private static void assertEquals(Object o1, Object o2) {
if (!o1.equals(o2)) {
throw new AssertionError("\n expected: " + o1 + "\n actual: " + o2);
}
}
private static Map<String, String> getO1() {
Map<String, String> nvps = new HashMap<String, String>();
nvps.put("timestamp", "1326382770000");
nvps.put("length", "246");
return nvps;
}
private static Map<String, String> getO2() {
Map<String, String> nvps = new HashMap<String, String>();
nvps.put("timestamp", "0");
nvps.put("length", "0");
return nvps;
}
private static ObjectOutputStream getOOS(File storageFile)
throws IOException {
if (storageFile.exists()) {
// this is a workaround so that we can append objects to an existing file
return new AppendableObjectOutputStream(new FileOutputStream(storageFile, true));
} else {
return new ObjectOutputStream(new FileOutputStream(storageFile));
}
}
private static ObjectInputStream getOIS(FileInputStream fis)
throws IOException {
long pos = fis.getChannel().position();
return pos == 0 ? new ObjectInputStream(fis) :
new AppendableObjectInputStream(fis);
}
private static class AppendableObjectOutputStream extends
ObjectOutputStream {
public AppendableObjectOutputStream(OutputStream out)
throws IOException {
super(out);
}
@Override
protected void writeStreamHeader() throws IOException {
// do not write a header
}
}
private static class AppendableObjectInputStream extends ObjectInputStream {
public AppendableObjectInputStream(InputStream in) throws IOException {
super(in);
}
@Override
protected void readStreamHeader() throws IOException {
// do not read a header
}
}
}
ObjectInputStream
来匹配每个 ObjectOutputStream
。我不知道有没有一种方法可以将完整的 ObjectInputStream
的状态传输到 ObjectOutputStream
中(在纯 Java 中进行完整重新实现有点棘手)。
ObjectOutputStream
吗? - OscarRyz