code

ObjectOutputStream에 추가

codestyles 2021. 1. 7. 08:00
반응형

ObjectOutputStream에 추가


에 추가 할 수 ObjectOutputStream없습니까?

개체 목록에 추가하려고합니다. 다음 스 니펫은 작업이 완료 될 때마다 호출되는 함수입니다.

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

나는 얼마나 많은 물건이 있을지 모르기 때문에 나는 예외가없는 동안 읽고있다. Google이 말한 바에 따르면 이것이 불가능합니다. 방법을 아는 사람이 있는지 궁금합니다.


트릭은 다음과 같습니다. 하위 클래스 ObjectOutputStreamwriteStreamHeader메서드 재정의 :

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

}

이를 사용하려면 히스토리 파일이 존재하는지 여부를 확인하고이 추가 가능한 스트림 (파일이있는 경우 = we append = 헤더를 원하지 않음) 또는 원본 스트림 (파일이없는 경우 = 헤더가 필요합니다).

편집하다

나는 수업의 첫 번째 이름이 마음에 들지 않았습니다. 이게 더 낫다 : '어떻게 하는가'보다는 '무엇을위한 것인지'를 설명한다.

편집하다

명확히하기 위해이 스트림은 기존 파일에 추가하기위한 것임을 다시 한 번 이름을 변경했습니다. 개체 데이터 파일 을 만드는 데 사용할 수 없습니다 .

편집하다

에 전화를 추가 reset()한 후 이 문제가 단지 오버라이드가 원래 버전 것으로 나타났다 writeStreamHeader아무 조합은없는 몇 가지 조건을 읽을 수 없습니다 스트림을 만들 수 아래.


는 AS API는 말했다의 ObjectOutputStream생성자는 기본이되는 스트림에 직렬화 스트림 헤더를 기록합니다. 그리고이 헤더는 파일 시작 부분에 한 번만있을 것으로 예상됩니다. 그래서 전화

new ObjectOutputStream(fos);

온 여러 번 FileOutputStream같은 파일을 참조 헤더를 여러 번 손상된 파일을 작성합니다.


직렬화 된 파일의 정확한 형식 때문에 추가하면 실제로 파일이 손상됩니다. 모든 객체를 동일한 스트림의 일부로 파일에 써야합니다. 그렇지 않으면 객체를 예상 할 때 스트림 메타 데이터를 읽을 때 충돌이 발생합니다.

자세한 내용 Serialization Specification거나 Roedy Green이 기본적으로 방금 말한 내용을 말하는 스레드를 읽을 수 있습니다.


이 문제를 피하는 가장 쉬운 방법은 데이터를 쓸 때 각 객체 다음에 닫는 대신 OutputStream을 열어 두는 것입니다. reset()메모리 누수를 피하기 위해 호출 하는 것이 좋습니다.

대안은 파일을 일련의 연속 ObjectInputStream으로 읽는 것입니다. 그러나 이렇게하려면 읽은 바이트 수를 세고 (FilterInputStream으로 구현할 수 있음) InputStream을 닫고 다시 열고 해당 바이트를 건너 뛰고 ObjectInputStream ()으로 래핑해야합니다.


객체를 추가 할 때마다 파일의 모든 현재 데이터를 읽고 복사 한 다음 파일에 모두 덮어 쓰는 것은 어떻습니까?


새 파일을 추가하고 생성하는 데 사용할 수있는 클래스를 만들기 위해 허용 된 솔루션을 확장했습니다.

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

    }

}

참조 URL : https://stackoverflow.com/questions/1194656/appending-to-an-objectoutputstream

반응형