Unity优化:解析表优化

在开发项目时,我们经常会用到解析配置表,读取的文件类型有csv/xls/xlsx/txt/json,无论是哪一种,都差不太多,最后都会出现字符串操作,当大量操作字符串时,string类型会额外消耗大量内存,会极大影响性能,所以使用StringBuilder类来操作字符串会更加高效。

使用StringBuilder类需要引入命名空间

using System.Text;

这是一个半成品的解析文件脚本,我的xlsx第一行是标注因此不读取

using Excel;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Text;
using UnityEngine;

public class ObjectsInfo : MonoBehaviour
{
    public static ObjectsInfo instance;

    //文本路径  StreamingAssets文件夹下
    private string excelname = "/Object.xlsx";
    

    //字典    id 物品
    private Dictionary ObejectDic = new Dictionary();


    private void Awake()
    {
        instance = this;
        ParseText();
    }
    //文本解析
    private void ParseText()
    {
        //打开文本  读
        FileStream stream = File.Open(Application.streamingAssetsPath + excelname, FileMode.Open, FileAccess.Read, FileShare.Read);
        //读取文件流
        IExcelDataReader excelRead = ExcelReaderFactory.CreateOpenXmlReader(stream);
        //转化为数据
        DataSet result = excelRead.AsDataSet();

        //获取表格行数
        int row = result.Tables[0].Rows.Count;
        //获取表格列数
        int col = result.Tables[0].Columns.Count;
        //数组存储
        StringBuilder[] infosArray = new StringBuilder[row - 1];

        Debug.Log(result.Tables[0].Rows[1][0].ToString());
        //每一行
        for (int i=0; i< row-1; i++)
        {
            infosArray[i] = new StringBuilder();
            for (int j=0; j< col;j++)
            {
                infosArray[i].Append(result.Tables[0].Rows[i+1][j]);
                if(j!=col-1)
                {
                    infosArray[i].Append('|');
                }
            }
            Debug.Log(infosArray[i]);
        }

        //每行
        for (int i = 0; i < row-1; i++)
        { 
            //物体
            ObjectInfo info = new ObjectInfo();
            string[] temp=infosArray[i].ToString().Split('|');
            info.id = int.Parse(temp[0]);
            info.name = temp[1];
            info.type = (ObjectType)System.Enum.Parse(typeof(ObjectType), temp[2]);
            info.uipath = temp[3];
            info.des = temp[4];
            ObejectDic.Add(info.id,info);
        }

        //关闭文件
        if (stream != null)
        {
            stream.Close();
        }
    }

    //根据id获取物品
    public ObjectInfo GetObjectInfoById(int id)
    {
        ObjectInfo info = null;
        ObejectDic.TryGetValue(id, out info);
        return info;
    }
}


public enum ObjectType
{
    //武器
    GUN=0
}

public class ObjectInfo
{
    //id
    public int id;
    //物品名字
    public string name;
    //类型
    public ObjectType type;
    //UI图片路径
    public string uipath;
    //描述
    public string des;
}

有人会说为什么要把读出的数据先用字符串拼接存起来?然后后面又拆分,为什么不直接将读出的数据转化为相应类型存进去?

首先如果直接转与存是可以实现的,但是你想想,每一行的每一列都需要进行转自符号串加上转类型操作,数据量大的时候.ToString()方法会对性能产生影响,所以先用StringBuilder拼接再分开节约内存,提升性能。

.ToString()方法

在C#中,调用.ToString()方法本身并不会显著地消耗性能。ToString()方法是一个常见的方法,用于将对象转换为字符串表示形式。

然而,需要注意的是,如果在大量的循环或频繁的操作中频繁地调用.ToString()方法,可能会对性能产生一些影响。这是因为每次调用.ToString()方法都会创建一个新的字符串对象,并且在内存中分配新的空间来存储转换后的字符串。

如果在性能敏感的代码中需要频繁地将对象转换为字符串,可以考虑使用其他更高效的方法,例如使用StringBuilder类来构建字符串,或者使用格式化字符串的方法,如string.Format()或插值字符串。

总之,对于一般的使用情况,调用.ToString()方法不会带来明显的性能问题。但在特定的性能要求下,可以考虑使用更高效的字符串操作方法来优化代码。

C#中如何将StringBuilder的内容转化为string

在C#中,可以使用StringBuilder的ToString()方法将StringBuilder的内容转化为string类型。ToString()方法会返回StringBuilder对象中存储的字符串。

StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("Hello");
stringBuilder.Append(" ");
stringBuilder.Append("World");

string result = stringBuilder.ToString();
Console.WriteLine(result); // 输出:Hello World

在上述示例中,首先创建了一个StringBuilder对象,并使用Append()方法向其添加了多个字符串。然后,通过调用ToString()方法将StringBuilder的内容转化为string类型,并将结果赋值给result变量。最后,通过Console.WriteLine()方法输出结果。

需要注意的是,一旦调用ToString()方法,StringBuilder对象的内容将被转化为string类型,并且StringBuilder对象将被重置为空。因此,在需要多次使用StringBuilder对象时,应该在每次使用之前重新构建它。

这样看挺费时间的,所以我们看到核心代码

        //转化为数据
        DataSet result = excelRead.AsDataSet();

        //获取表格行数
        int row = result.Tables[0].Rows.Count;
        //获取表格列数
        int col = result.Tables[0].Columns.Count;
        //数组存储
        StringBuilder[] infosArray = new StringBuilder[row - 1];

        Debug.Log(result.Tables[0].Rows[1][0].ToString());
        //每一行
        for (int i=0; i< row-1; i++)
        {
            infosArray[i] = new StringBuilder();
            for (int j=0; j< col;j++)
            {
                infosArray[i].Append(result.Tables[0].Rows[i+1][j]);
                if(j!=col-1)
                {
                    infosArray[i].Append('|');
                }
            }
            Debug.Log(infosArray[i]);
        }

        //每行
        for (int i = 0; i < row-1; i++)
        { 
            //物体
            ObjectInfo info = new ObjectInfo();
            string[] temp=infosArray[i].ToString().Split('|');
            info.id = int.Parse(temp[0]);
            info.name = temp[1];
            info.type = (ObjectType)System.Enum.Parse(typeof(ObjectType), temp[2]);
            info.uipath = temp[3];
            info.des = temp[4];
            ObejectDic.Add(info.id,info);
        }

其次无论你优化得多好,读取总需要时间,因此提前读,一般我们可以在切到此场景前的一个场景加载这个,比如:我切换场景时不销毁某个物体,加载一个过渡场景,停留一定时间,并为其添加解析的脚本,然后在切换到目标场景,那么我们在下一个场景依旧能得到数据,并且游戏也不会感受到卡顿。

你可能感兴趣的:(Unity3D,游戏引擎,游戏,c#,unity)