A NullReferenceException
бросается, когда мы пытаемся получить доступ к свойствам нулевого объекта или когда значение строки становится пустым, и мы пытаемся получить доступ к строковым методам.
Например:
string str = string.Empty;
str.ToLower(); // throw null reference exception
Public Class Person {
public string Name { get; set; }
}
Person objPerson;
objPerson.Name /// throw Null refernce Exception
Вот трюк: подкласс 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();
}
}
Чтобы использовать его, просто проверьте, существует ли файл истории или нет, и создайте экземпляр этого добавочного потока (в если файл существует = мы append = нам не нужен заголовок) или исходный поток (в случае, если файл не существует = нам нужен заголовок).
Изменить
Я был недоволен первым наименованием класса. Это лучше: он описывает «что это такое», а не «как это сделано»
Edit
Изменено имя еще раз, чтобы уточнить, что этот поток предназначен только для добавление к существующему файлу. Он не может быть использован для создания файла new с данными объекта.
Редактировать
Добавлен вызов reset()
после этого вопроса показал, что исходная версия, которая просто переопределила writeStreamHeader
как no-op, в некоторых случаях могла создать поток, который не мог быть прочитан.
Как говорит API , конструктор ObjectOutputStream
записывает заголовок потока сериализации в базовый поток. И этот заголовок ожидается только один раз, в начале файла. Поэтому несколько раз нажимать
new ObjectOutputStream(fos);
на FileOutputStream
, который ссылается на один и тот же файл, будет писать заголовок несколько раз и испортить файл.
Самый простой способ избежать этой проблемы - сохранить OutputStream открытым при записи данных, а не закрывать его после каждого объекта. Вызов reset()
может быть целесообразным, чтобы избежать утечки памяти.
Альтернативой может быть чтение файла как серии последовательных ObjectInputStreams. Но это требует от вас подсчитывать, сколько байтов вы читаете (это может быть реализовано с помощью FilterInputStream), затем закрыть InputStream, снова открыть его, пропустить это много байтов и только затем обернуть его в ObjectInputStream ().
Из-за точного формата сериализованного файла добавление действительно испортит его. Вы должны записать все объекты в файл как часть одного и того же потока, иначе он будет сбой при чтении метаданных потока, когда он ожидает объект.
Вы можете прочитать спецификацию Serialization Specification для более подробной информации или (проще) прочитать эту нить , где Roedy Green говорит в основном то, что я только что сказал.
Как насчет каждого раза, когда вы добавляете объект, читаете и копируете все текущие данные в файле, а затем переписываете все вместе в файл.