«Конец потока, обнаруженный до завершения синтаксического анализа». При десериализации из файла

#c# #.net #visual-studio-2010

#c# #.net #visual-studio-2010

Вопрос:

У меня следующая проблема: когда я запускаю свое приложение, настройки загружаются из файла, поэтому десериализуются, когда это происходит, я получаю следующую ошибку:

{"End of Stream encountered before parsing was completed."} System.Exception {System.Runtime.Serialization.SerializationException}

Код сериализации:

 using(FileStream write = new FileStream(SETTINGSPATH,FileMode.Create,FileAccess.Write)
{
  BinaryFormatter formatter = new BinaryFormatter();
  formatter.Serialize(write,settings);
}
  

Метод десериализации:

 using (FileStream read = new FileStream(SETTINGSPATH,FileMode.Open,FileAccess.Read))
{
  BinaryFormatter formatter = new BinaryFormatter();
  read.Position = 0;
  settings = (Settings)formatter.Deserialize(read); // settings is declared as Settings object
}
  

Класс настроек:

 using System;
using System.Collections.Generic;  
using System.Linq;
using System.Runtime.Serialization;
using System.Text;

namespace Serie_Counter.Overkoepelend
{
public delegate void SelectedMoveOptionChanged(AutoMoveOption selectedOption, int checkInterval = 30 );

public delegate void EnableAutoMoveChanged(bool EnableAutoMove);

[Serializable]
public class Settings
{
    private string serieListSavePath;
    private bool autoStart;
    private bool enableRember;
    private bool closeWithMainForm;
    private int warningDelay;
    // moving options
    private bool enableAutoMove;
    private string rootFolder;
    private int checkInterval;
    private AutoMoveOption selectedMoveOption;

    public event SelectedMoveOptionChanged selectedMoveOptionChanged;
    public event EnableAutoMoveChanged enableAutoMoveChanged;

    #region Properties

    public string SerieListSavePath
    {
        get
        {
            return serieListSavePath;
        }
        set
        {
            serieListSavePath = value;
        }
    }

    public bool AutoStart
    {
        get
        {
            return autoStart;
        }
        set
        {
            autoStart = value;
        }
    }

    public bool EnableRember
    {
        get
        {
            return enableRember;
        }
        set
        {
            enableRember = value;
        }
    }

    public bool CloseWithMainForm
    {
        get
        {
            return closeWithMainForm;
        }
        set
        {
            closeWithMainForm = value;
        }
    }

    public int WarningDelay
    {
        get
        {
            return warningDelay;
        }
        set
        {
            warningDelay = value;
        }
    }

    public bool EnableAutoMove
    {
        get
        {
            return enableAutoMove;
        }
        set
        {
            enableAutoMove = value;
            if (enableAutoMove != null) enableAutoMoveChanged(value);
        }
    }

    public string RootFolder
    {
        get
        {
            return rootFolder;
        }
        set
        {
            rootFolder = value;
        }
    }

    public int CheckInterval
    {
        get
        {
            return checkInterval;
        }
        set
        {
            checkInterval = value;
        }
    }

    public AutoMoveOption SelectedMoveOption
    {
        get
        {
            return selectedMoveOption;
        }
        set
        {
            selectedMoveOption = value;
            selectedMoveOptionChanged(value, checkInterval);

        }
    }

    #endregion



    public Settings(string serieListSavePath)
    {
        this.serieListSavePath = serieListSavePath;
    }

    public Settings()
    {
        this.serieListSavePath = "series.xml";
        warningDelay = -1;
    }

    [OnDeserialized]
    private void SetValuesOnDeserialized(StreamingContext context)
    {
        selectedMoveOptionChanged = null;
        enableAutoMoveChanged = null;

    }
  

Кто-нибудь знает, почему это происходит?

Если вам нужна дополнительная информация или код, пожалуйста, проверьте http://seriescounter.codeplex.com /

Приветствует Томаса

РЕДАКТИРОВАТЬ: Может ли проблема заключаться в том, что десериализация завершается неудачно, потому что я сериализую события в? Я только что протестировал это, убедившись, что события равны нулю при сериализации. и до сих пор ошибка больше не повторялась.

http://seriescounter.codeplex.com/SourceControl/changeset/changes/12646

Комментарии:

1. Вы проверили, существует ли файл и не поврежден ли он?

2. Если вы просто сохраняете настройки, то эмпирическое правило заключается в использовании читаемого формата, такого как XML, для сохранения настроек.

3. Пожалуйста, опубликуйте код, который вы используете для сериализации, и сохраните настройки. Это нелегко найти в ссылке на codeplex, которую вы опубликовали. Я подозреваю, что может отсутствовать Flush . Кроме того, вы неправильно запускаете свое enableAutoMoveChanged событие. Вы должны сначала скопировать событие в локальную переменную, var ev=enableAutoMoveChanged; затем проверить, ev не равно ли оно null, затем запустить его ev(value);

4. Я проверяю, существует ли файл, код сериализации: <code> используя(FileStream write = new FileStream(SETTINGSPATH,FileMode. Создать,FileAccess. Запись)) { BinaryFormatter formatter = new BinaryFormatter(); форматировщик. Сериализовать (запись, настройки); } </code> может быть, у меня ошибка, потому что я сериализую события, чтобы?

5. Я бы сериализовал в читаемый формат (xml / json) и посмотрел, что не так с файлом настроек

Ответ №1:

Ваша проблема в наборе изменений 12594, вы добавили событие checkIntervalChanged в класс Settings. Это добавило в класс невидимое поле, которое также сериализуется. Но теперь у вас проблема с настройкой файлов, которые были сохранены с предыдущей версией, данные сериализации не содержат этого поля, результатом является исключение.

Вы можете спасти его следующим образом:

     [Serializable]
    public class Settings {
        [NonSerialized]
        private CheckIntervalChanged checkIntervalChangedBacking;

        public event CheckIntervalChanged CheckIntervalChanged {
            add { checkIntervalChangedBacking  = value; }
            remove { checkIntervalChangedBacking -= value; }
        }
        // etc..
    }
  

Атрибут [Несериализованный] теперь гарантирует, что резервное поле не будет сериализовано. Вы все равно никогда не захотите сериализовать события.

В общем, вам нужно быть осторожным с двоичной сериализацией, с управлением версиями сложно иметь дело. Добавление поля может и мгновенно превратит любые сохраненные данные в мусор. Есть хорошие подсказки в «версий сериализациюраздел» в библиотеке MSDN.

Комментарии:

1. Добавленные поля в класс не должны влиять на десериализацию из более старой версии, поскольку неизвестные поля будут просто заполнены значениями по умолчанию. Также проще не сериализовывать события, используя спецификатор поля для атрибута, т.е. [field: NonSerialized] при объявлении события.

2. Я получил ту же ошибку и нашел эту страницу. Однако, как оказалось, моя проблема в том, что я добавил новый класс и забыл добавить атрибут [Serializable] к классу, так что он изначально не был сериализован правильно. Затем, когда он пытается десериализовать, я получил эту ошибку. После добавления атрибута [Serializable] к классу все работает нормально.