Добавление к ObjectOutputStream

Разделить следующую строку на 2:

bf = Entry(Geom, width=5, justify= RIGHT, font="Arial 12").grid(column=1, row=0)

вот так

bf = Entry(Geom, width=5, justify= RIGHT, font="Arial 12")
bf.grid(column=1, row=0)

На данный момент bf не является виджетом Entry, но None возвращено из grid() Также обратите внимание, что обычно вы используете переменную, например IntVar, то есть привязка к виджету входа

55
задан Jonas 15 October 2011 в 05:54
поделиться

5 ответов

Вот трюк: создайте подкласс 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();
  }

}

Чтобы использовать его, просто проверьте, существует ли файл истории или нет и создать экземпляр либо этого добавляемого потока (в случае, если файл существует = мы добавляем = нам не нужен заголовок), либо исходного потока (в случае, если файл не существует = нам нужен заголовок).

Изменить

Я не был доволен первым названием класса. Этот лучше: он описывает «для чего», а не «как это делается».

Изменить

Имя изменено еще раз, чтобы уточнить, что этот поток предназначен только для добавления к существующему файлу. Его нельзя использовать для создания нового файла с данными объекта.

77
ответ дан 7 November 2019 в 07:19
поделиться

Я расширил принятое решение создать класс, который может использоваться и для добавления и для создания нового файла.

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

    }

}
0
ответ дан 7 November 2019 в 07:19
поделиться

Как сказано в API , конструктор ObjectOutputStream записывает заголовок потока сериализации в базовый поток. Ожидается, что этот заголовок будет только один раз, в начале файла. Таким образом, вызов

new ObjectOutputStream(fos);

несколько раз в FileOutputStream , который ссылается на один и тот же файл, приведет к многократной записи заголовка и повреждению файла.

конструктор ObjectOutputStream записывает заголовок потока сериализации в базовый поток. И ожидается, что этот заголовок будет только один раз, в начале файла. Таким образом, вызов

new ObjectOutputStream(fos);

несколько раз в FileOutputStream , который ссылается на один и тот же файл, приведет к многократной записи заголовка и повреждению файла.

конструктор ObjectOutputStream записывает заголовок потока сериализации в базовый поток. И ожидается, что этот заголовок будет только один раз, в начале файла. Таким образом, вызов

new ObjectOutputStream(fos);

несколько раз в FileOutputStream , который ссылается на один и тот же файл, приведет к многократной записи заголовка и повреждению файла.

13
ответ дан 7 November 2019 в 07:19
поделиться

Из-за точного формата сериализованного файла добавление действительно повредит его. Вы должны записать все объекты в файл как часть одного и того же потока, иначе произойдет сбой при чтении метаданных потока, когда он ожидает объект.

Вы можете прочитать Спецификацию сериализации , чтобы узнать больше. Детали,

7
ответ дан 7 November 2019 в 07:19
поделиться

Самый простой способ избежать этой проблемы - оставить OutputStream открытым при написании данные, а не закрывать их после каждого объекта. Вызов reset () может быть целесообразным, чтобы избежать утечки памяти.

Альтернативой может быть чтение файла как серии последовательных ObjectInputStreams. Но это требует, чтобы вы подсчитали, сколько байтов вы прочитали (это можно реализовать с помощью FilterInputStream), затем закройте InputStream, откройте его снова, пропустите это количество байтов и только затем заключите его в ObjectInputStream ().

6
ответ дан 7 November 2019 в 07:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: