2010-01-19 16 views
10

지금은 객체 추가를 시도 할 때 java.io.StreamCorruptedException이됩니다. 나는 그것을 극복하기위한 방법을 찾기 위해 인터넷을 수색했다. 지금까지 찾은 대답은 할 수 없다는 것입니다. 이 문제를 해결하는 방법은 개체를 목록에 쓴 다음 목록을 파일에 쓰는 것입니다.기존 java.io.ObjectStream에 어떻게 추가 할 수 있습니까?

하지만 새 개체를 추가 할 때마다 파일을 덮어 써야합니다. 그것은 초과 근무 시간에 최적의 솔루션이 아닌 것 같습니다.

개체를 기존 개체 스트림에 추가 할 수있는 방법이 있습니까?

+3

질문이 있으십니까? – danben

+0

지속성을 위해 데이터베이스를 사용할 수 있습니까? – Asaph

+0

@danben : 네, 문제는 파일에 객체를 추가 할 수 있는지 여부입니다. @Asaph : 그렇게 할 수는 있지만 추가가 객체에 대해 아니오인지 알고 싶습니다. 제 질문으로 그 사실을 분명히 알 수없는 경우 Sry. – starcorn

답변

5

사실 꽤 쉽게 할 수 있습니다. 기존 스트림에 추가 할 때 두 번째 헤더가 파일의 중간에 쓰여지지 않도록 writeStreamHeader을 대체하는 ObjectOutStream의 서브 클래스를 사용해야합니다. 예를 들어

class NoHeaderObjectOutputStream extends ObjectOutputStream { 
    public NoHeaderObjectOutputStream(OutputStream os) { 
    super(os); 
    } 
    protected void writeStreamHeader() {} 
} 

그런 다음 전체 파일을 읽는 데 표준 ObjectInputStream을 사용하십시오.

+0

write (byte [] b, int off, int len, boolean copy)는 불행히도 private 메서드 writeBlockHeader를 사용합니다. – stacker

+0

멋지다. 작동한다. :) – starcorn

+0

+1 설명서에 나와있는 내용을 읽었지 만 (문서가 나와 종종 자주 발생하므로) 지금까지는 이해하지 못했습니다. – OscarRyz

0

ObjectOutputStream과 일치하도록 ObjectInputStream을 새로 만들어야합니다. 나는 ObjectInputStream에서 ObjectOutputStream으로 상태를 옮기는 방법을 모른다. (완전히 재 구현하지 않아도된다. 어쨌든 순수 자바에서는 조금 까다 롭다.)

5

나는이 주제에 발견 한 가장 좋은 기사는 다음과 같습니다 ObjectOutputStream에 단순히 잘못 무시 http://codify.flansite.com/2009/11/java-serialization-appending-objects-to-an-existing-file/

은 "솔루션". 나는 방금 그 (두 소중한 시간을 낭비)에 의해 발생한 버그를 조사 완료했습니다. 뿐만 아니라 때때로 직렬화 된 파일을 손상시킬뿐만 아니라 예외를 던지거나 쓰레기 데이터 (필드 혼합)를 제공하지 않고도 읽을 수있었습니다.

솔루션 # 1 : 그 기사에서 언급 한 바와 같이

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 
     } 
    } 
} 

, 당신은 다음 방법 중 하나를 사용할 수 있습니다 불신을 위해, 나는 문제를 노출 몇 가지 코드를 부착하고있어 가짜 단일 스트림

에서 여러 파일 ...

다음,536,913,632를 작성하는있는 ByteArrayOutputStream에 "거래"를 쓰기 10 ByteArrayOutputStream의 길이와 내용을 DataOutputStream을 통해 파일에 저장합니다.

해결 방법 # 2 : 다시 열고 또 다른 솔루션을 사용하여 파일 위치 저장이 포함

건너 뛰기 :

long pos = fis.getChannel().position(); 

, 파일을 닫는 파일을 재개하고를 읽기 전에이 위치 에 건너 뛰는를 다음 거래.

+0

다음은 솔루션 # 1을 구현하는 한 쌍의 함수 (Scala에서)이다. –

2

코드 노출 문제에 대해 George Hategan에게 감사드립니다.. 나는 잠시 그것을 조사했다. 그런 다음, 그것은 나를 때렸다.데이터를 작성하는 하위 분류 writeStreamHeader()의 재정의와 ObjectOutputStream에 방법을 사용하는 경우, 당신은 의 재정의와 병렬 하위 분류 ObjectInputStream를를 사용해야합니다 readStreamHeader() 데이터를 읽는 방법입니다. 물론 객체를 작성하고 읽는 여러 구현간에 지그재그가 가능하지만 쓰기/읽기 프로세스에서 해당 하위 클래스 쌍을 사용하는 한 - 잘하면 좋을 것입니다. 남자 이름.

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 
     } 
    } 
}