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이 말한 바에 따르면 이것이 불가능합니다. 방법을 아는 사람이 있는지 궁금합니다.
트릭은 다음과 같습니다. 하위 클래스 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();
}
}
이를 사용하려면 히스토리 파일이 존재하는지 여부를 확인하고이 추가 가능한 스트림 (파일이있는 경우 = 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
'code' 카테고리의 다른 글
| C ++의 해시 테이블? (0) | 2021.01.07 |
|---|---|
| Solr 쿼리에서 특정 필드를 검색합니까? (0) | 2021.01.07 |
| CMake의 set_target_properties가 CMAKE_CXX_FLAGS를 재정의합니까? (0) | 2021.01.07 |
| PostgreSQL 사용자에 대한 빈 암호 설정 (0) | 2021.01.07 |
| sed를 사용하여 일치하는 두 패턴 사이의 모든 줄 삭제 (0) | 2021.01.07 |