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 |