SerializeException:尝试反序列化空流错误

时间:2019-03-20 19:20:17

标签: c# unity3d

根据Kryzarel在YouTube上的教程,我一直在为库存系统统一实施保存系统。 这是访问序列化和反序列化以及与保存系统相关的其他脚本的代码。

FileReadWrite.cs

using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

    public static class FileReadWrite
    {
        public static void WriteToBinaryFile<T>(string filePath , T objectToWrite)
        {
            using (Stream stream = File.Open(filePath, FileMode.Open))
            {
                var binaryFormatter = new BinaryFormatter();
                binaryFormatter.Serialize(stream, objectToWrite);
            }
        }

        public static T ReadFromBinaryFile<T>(string filePath)
        {
            using (Stream stream = File.Open(filePath, FileMode.Open))
            {
                var binaryFormatter = new BinaryFormatter();
                return (T)binaryFormatter.Deserialize(stream);
            }


        }

    }

ItemSaveIO.cs

using UnityEngine;

public static class ItemSaveIO
{
    private static readonly string baseSavePath;
    static ItemSaveIO()
    {
        baseSavePath = Application.persistentDataPath;
    }

    public static void SaveItems(ItemContainerSaveData items, string fileName)
    {
        FileReadWrite.WriteToBinaryFile(baseSavePath + "/" + fileName + ".dat", items);
    }

    public static ItemContainerSaveData LoadItems(string fileName)
    {
        string filePath = baseSavePath + "/" + fileName + ".dat";

        if(System.IO.File.Exists(filePath))
        {
            return FileReadWrite.ReadFromBinaryFile<ItemContainerSaveData>(filePath);
        }
        else
        {
            Debug.LogError("Save file not found in" + filePath);
            return null;
        }

    }
}

ItemSaveData.cs

    using System;


    [Serializable]
    public class ItemSlotSaveData
    {
        public string ItemID;

        public ItemSlotSaveData(string itemID)
        {
            ItemID = itemID;
        }
    }

    [Serializable]
    public class ItemContainerSaveData
    {
        public ItemSlotSaveData[] SavedSlots;

        public ItemContainerSaveData(int numItems)
        {
            SavedSlots = new ItemSlotSaveData[numItems];
        }
    }

ItemSaveManager.cs

 using System.Collections;
    using System;
    using System.Collections.Generic;
    using UnityEngine;

    public class ItemSaveManager : MonoBehaviour
    {
        [SerializeField] ItemDatabase itemDatabase;

        private const string InventoryFileName = "Inventory";
        private const string EquipmentFileName = "Equipment";

        public void LoadInventory(Character character)
        {
            ItemContainerSaveData savedSlots = ItemSaveIO.LoadItems(InventoryFileName);
            if (savedSlots == null) return;

            character.Inventory.Clear();

            for(int i = 0; i < savedSlots.SavedSlots.Length; i++)
            {
                ItemSlot itemSlot = character.Inventory.ItemSlots[i];
                ItemSlotSaveData savedSlot = savedSlots.SavedSlots[i];

                if(savedSlot == null)
                { 
                    itemSlot.Item = null;

                }
                else
                {
                    itemSlot.Item = itemDatabase.GetItemCopy(savedSlot.ItemID);

                }
            }
        }

        public void LoadEquipment(Character character)
        {
            ItemContainerSaveData savedSlots = ItemSaveIO.LoadItems(EquipmentFileName);
            if (savedSlots == null) return;

            foreach (ItemSlotSaveData savedSlot in savedSlots.SavedSlots)
            {
                if(savedSlots == null)
                {
                    continue;
                }


                Item item = itemDatabase.GetItemCopy(savedSlot.ItemID);
                character.Inventory.AddItem(item);
                character.Equip((EquippableItem)item);
            }

        }

        public void SaveInventory(Character character)
        {
            SaveItems(character.Inventory.ItemSlots, InventoryFileName);
        }

        public void SaveEquipment(Character character)
        {
            SaveItems(character.EquipmentPanel.EquipmentSlots, EquipmentFileName);
        }

        private void SaveItems(IList<ItemSlot> itemSlots, string fileName)
        {
            var saveData = new ItemContainerSaveData(itemSlots.Count);

            for(int i = 0; i < saveData.SavedSlots.Length; i++)
            {
                ItemSlot itemSlot = itemSlots[i];

                if(itemSlot.Item == null)
                {
                    saveData.SavedSlots[i] = null;
                }
                else
                {
                    saveData.SavedSlots[i] = new ItemSlotSaveData(itemSlot.Item.ID);
                }
            }
            ItemSaveIO.SaveItems(saveData, fileName);
        }

    }

ItemDatabase.cs

using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif


[CreateAssetMenu]
public class ItemDatabase : ScriptableObject
{
    [SerializeField] Item[] items;

    public Item GetItemReference(string itemID)
    {
        foreach(Item item in items)
        {
            if(item.ID == itemID)
            {
                return item;
            }
        }
        return null;
    }

    public Item GetItemCopy(string itemID)
    {
        Item item = GetItemReference(itemID);
        if (item == null) return null;
        return item.GetCopy();
    }
#if UNITY_EDITOR
    private void OnValidate()
    {
        LoadItems();
    }

    private void OnEnable()
    {
        EditorApplication.projectWindowChanged -= LoadItems;
    }

    private void OnDisable()
    {
        EditorApplication.projectWindowChanged -= LoadItems;
    }

    private void LoadItems()
    {
        items = FindAssetsByType<Item>("Assets");
    }

    public static T[] FindAssetsByType<T>(params string[] folders) where T : Object
    {
        string type = typeof(T).ToString().Replace("UnityEngine.", "");

        string[] guids;
        if (folders == null || folders.Length == 0)
        {
            guids = AssetDatabase.FindAssets("t:" + type);
        }
        else
        {
            guids = AssetDatabase.FindAssets("t:" + type, folders);
        }

        T[] assets = new T[guids.Length];

        for (int i = 0; i < guids.Length; i++)
        {
            string assetPath = AssetDatabase.GUIDToAssetPath(guids[i]);
            assets[i] = AssetDatabase.LoadAssetAtPath<T>(assetPath);
        }
        return assets;
    }
#endif
}

在Character脚本Awake()函数中最后2条语句,

 itemSaveManager.LoadEquipment(this);

 itemSaveManager.LoadInventory(this);

和OnDestroy()函数中的2条语句

    itemSaveManager.SaveEquipment(this);

    itemSaveManager.SaveInventory(this);

这里可能出了什么问题? 另外,这是一个例外:

SerializationException: Attempting to deserialize an empty stream.
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize (System.IO.Stream serializationStream, System.Runtime.Remoting.Messaging.HeaderHandler handler, System.Boolean fCheck, System.Boolean isCrossAppDomain, System.Runtime.Remoting.Messaging.IMethodCallMessage methodCallMessage) (at <d7ac571ca2d04b2f981d0d886fa067cf>:0)
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize (System.IO.Stream serializationStream, System.Runtime.Remoting.Messaging.HeaderHandler handler, System.Boolean fCheck, System.Runtime.Remoting.Messaging.IMethodCallMessage methodCallMessage) (at <d7ac571ca2d04b2f981d0d886fa067cf>:0)
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize (System.IO.Stream serializationStream, System.Runtime.Remoting.Messaging.HeaderHandler handler, System.Boolean fCheck) (at <d7ac571ca2d04b2f981d0d886fa067cf>:0)
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize (System.IO.Stream serializationStream, System.Runtime.Remoting.Messaging.HeaderHandler handler) (at <d7ac571ca2d04b2f981d0d886fa067cf>:0)
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize (System.IO.Stream serializationStream) (at <d7ac571ca2d04b2f981d0d886fa067cf>:0)
FileReadWrite.ReadFromBinaryFile[T] (System.String filePath) (at Assets/Scripts/SaveFile/FileReadWrite.cs:20)
ItemSaveIO.LoadItems (System.String fileName) (at Assets/Scripts/SaveFile/ItemSaveIO.cs:22)
ItemSaveManager.LoadEquipment (Character character) (at Assets/Scripts/SaveFile/ItemSaveManager.cs:40)
Character.Awake () (at Assets/Scripts/Character.cs:62)

1 个答案:

答案 0 :(得分:0)

FileMode方法中的流的ReadFromBinaryFileFileMode.Create更改为FileMode.Open

我猜想,当您使用ReadFromBinaryFile调用FileMode.Create时,会清除使用WriteToBinaryFile创建的文件,这就是为什么您得到空流的原因。

这是它的外观:

public static class FileReadWrite
{
    public static void WriteToBinaryFile<T>(string filePath , T objectToWrite)
    {
        using (Stream stream = File.Open(filePath, FileMode.Create))
        {
            var binaryFormatter = new BinaryFormatter();
            binaryFormatter.Serialize(stream, objectToWrite);
        }
    }

    public static T ReadFromBinaryFile<T>(string filePath)
    {
        using (Stream stream = File.Open(filePath, FileMode.Open))
        {
            var binaryFormatter = new BinaryFormatter();
            return (T)binaryFormatter.Deserialize(stream);
        }


    }

}