建议保存除二进制格式.serialize以外的自定义C#类(包含各种大小的列表/数组)的过程?

时间:2018-06-29 16:45:57

标签: c# unity3d serialization binaryformatter

我希望用户能够在应用程序中创建网格样式的“地图”,将其保存到磁盘,然后与其他人共享。在基本的地图数据中,我希望用户输入他们的姓名,以便“声明”他们的作品。

为了更加安全,我正在考虑将地图类(带有艺术家名称,地图尺寸,其他有用的选项以及flat / 2D数组/列表[根据需要删除])保存为二进制。因此,XML(人类可读)可能不是我要使用的东西……但是我还没有完全反对XML,只是谨慎地停止“窃取”。

我一直在使用BinaryFormatter.Serialize方法,但是随着我的tiledata大小从200 * 200瓦片增加到300 * 300瓦片,反序列化所需的时间从6.5秒增加到33秒,并且继续增加以指数方式。

理想情况下,我希望能够存储2000 * 2000的地图数据。

因此,除了学习压缩技术(无论如何我都会做以减小文件大小)之外,我还在想是否建议使用其他序列化器。我已经看到有一些第三方软件可用,但是需要弄清楚它们是否与Unity兼容(是的。我是一个自学成才的noob gamedev)。

任何帮助将不胜感激。

为清晰起见,添加了当前测试代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

public class FileReaderTest : MonoBehaviour
{
    public int xlimit = 300;
    public int ylimit = 300;

    // Use this for initialization
    void Start()
    {
        Save();
    }


    // Update is called once per frame
    void Update()
    {
    if (Input.anyKeyDown)
        Load();
    }

    private void Save()
    {
        BinaryFormatter formatter = new BinaryFormatter();

        FileStream file = File.Open(Application.dataPath + "/saved.data", FileMode.OpenOrCreate);

        List<TestDataBaseEntry> mapTileData = new List<TestDataBaseEntry>();
        List<TestDataBaseEntry> extraMapTileData = new List<TestDataBaseEntry>();

        for (int x = 0; x < xlimit; x++)
        {
            for (int y = 0; y < ylimit; y++)
            {
                // Simulating random data
                mapTileData.Add(new TestDataBaseEntry(TileState.Filled, x, y));
            }
        }

        for (int x = 0; x < 5; x++)
        {
            for (int y = 0; y < 3; y++)
            {
                extraMapTileData.Add(new TestDataBaseEntry(TileState.Ignore, x, y));
            }
        }


        TestMapFile newFile = new TestMapFile("Mike", xlimit, ylimit, mapTileData, extraMapTileData);

        formatter.Serialize(file, newFile);
        file.Close();

        Debug.Log("saved");
    }

    private void Load()
    {
        float starttime = Time.realtimeSinceStartup;
        if (File.Exists(Application.dataPath + "/saved.data"))
        {
            using (FileStream file = File.Open(Application.dataPath + "/saved.data", FileMode.Open))
            {
                BinaryFormatter formatter = new BinaryFormatter();

                TestMapFile retrievedTestMapFile = (TestMapFile) formatter.Deserialize(file);
            }
        }

        Debug.Log("Loaded");
        Debug.Log("The process took " + (Time.realtimeSinceStartup - starttime));
    }

}

[Serializable]
public class TestDataBaseEntry
{
    public TileState tileState;
    public int x;
    public int y;

    public TestDataBaseEntry(TileState newTileState, int newX, int newY)
    {
        tileState = newTileState;
        x = newX;
        y = newY;
    }
}

[Serializable]
public class TestMapFile
{
    public int xSize;
    public int ySize;
    public List<TestDataBaseEntry> mapTileData = new List<TestDataBaseEntry>();
    public List<TestDataBaseEntry> mapExtraTileData = new List<TestDataBaseEntry>();
    public string createdBy;

    public TestMapFile(string artist, int newXSize, int newYSize, List<TestDataBaseEntry> newDB, List<TestDataBaseEntry> newExtraDB)
    {
        createdBy = artist;
        xSize = newXSize;
        ySize = newYSize;
        mapTileData = newDB;
        mapExtraTileData = newExtraDB;
    }
}

2 个答案:

答案 0 :(得分:0)

看一下protobuf-net。它不是那么易读,相当快并且占用更少的磁盘空间。 https://github.com/mgravell/protobuf-net

答案 1 :(得分:0)

好吧,我从Unity论坛上的上一篇帖子中获得了建议,并考虑了这里所说的一些观点,并创建了一些测试脚本-这是我的发现。

首先,在评论中提到的@Scott Hannen之后(在forum.Unity.com上一篇文章中也提到过),我尝试制作自己的de / serializer,我剥离了要放入的信息进入文件(并从文件中读取),并将时间缩短至0.13秒,以获取足够的信息来重新创建1920 * 1080尺寸的地图的地形。我正在使用的数据只是一个字符串,2个整数和一组布尔值。

因此,我然后回头再次查看BinaryFormatter。为了使比较彼此直接进行,我必须解决的最大区别是将自定义类TestDataBaseEntry的列表更改为bool数组(这是我在binarywriter中使用的数组)。仅此一项,就使读取文件的时间从300 * 300的地图大小的33.3秒减少到1920 * 1080的地图大小的11.1!巨大的改进-我猜想BinaryFormatter的某些过程需要进行大量的背景检查和错误检查?

所以它仍然不如我剥离的自定义序列化器快。但是,这仍然不是一个真正的比较,因为我仍在使用BinaryFormatter反序列化实际的类,而我正在使用BinaryWriter / BinaryReader分别反序列化该类的组件。

所以我还有更多测试要做,但是到目前为止,对我来说,解决方案似乎是使我要写入文件的信息不复杂,并删除尽可能多的自定义类型(?)。很有可能我从中读到了错误的答案...但是我会继续研究,看看能做什么。

非常感谢所有答复并提供其他途径供我研究的人。我仍将进一步研究这些知识,以扩展我的知识...加上其中之一(如protobuf-net)可能仍然是实施的更好解决方案;)

再次,谢谢。以后。

更新-第二天早上...

因此,我进行了另一项测试,这次将定制类完全剥离,并直接在文件中直接对相关部分进行序列化和反序列化。现在,BinaryFormatter不必在可序列化的自定义类中处理它了,我现在获得的读取时间为0.15秒-就像我在使用自己的自定义序列化器一样。

因此,我在您的所有帮助下都学到了非常有价值的东西-序列化基本类型而不是自定义类!

再次,非常感谢;)