Unity 3D 文件加密上 文件读取 组成对应数据类

版本:unity 5.4.1  语言:C#

 

实战核心技术来到了第五章,这一章我准备分两篇来分析一下其中的代码,这一篇重点讲一下文件的读取,以及获取到数据后如何反射出对应类。作者的注释寥寥数语,所以很多代码要自己去分析、尝试。

 

首先我们来看一下我们要读取的数据:

//character.csv
id,name,maxHp,atk,def,spd
1,Ex,100,10,5,7
2,pop,200,5,5,5
3,tang,150,7,8,9

一些角色的数据,定义的比较简单,然后是对应的类,或者说是bean:

// 角色类
[System.Serializable]   //序列化,能在Inspector中显示类成员变量,该参数不影响下面MyDataPath的配置
[MyDataPath("/Script/Encrypt/character.csv")]   //配置读取路径
public class Character
{
    public int id;  //一些属性
    public string name;
    public int maxHp;
    public int atk;
    public int def;
    public int spd;

    public override string ToString()
    {
        return "id = " + id + ", name = " + name + ", maxHp = " + maxHp + ", atk = " + atk + ", def = " + def + ", spd = " + spd;
    }
}


很好理解吧,不过可能大家没有看到过[MyDataPath(路径)]的写法,这是一种自定义的属性参数配置,具体说明如下:

/*
 * AttributeUsage声明一个Attribute的使用范围与使用原则
 *      All 可以对任何应用程序元素应用属性
 *      Assembly 可以对程序集应用属性
 *      Class 可以对类应用属性
 *      Constructor 可以对构造函数应用属性
 *      Delegate 可以对委托应用属性
 *      Enum 可以对枚举应用属性
 *      
 * 参数:
 *      AllowMultiple 为true,则返回特性可对单个实体应用多次
 *      Inherited 为false,则该特性不从特性化的派生类的类继承
 *      
 * 该参数所定义的类会自动生成一个去掉Attribute的参数,即MyDataPath,
 * 使用的时候以[MyDataPath(路径)]的形式就可以进行配置
 */
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class MyDataPathAttribute : Attribute
{
    public string filePath { get; set; }
    public MyDataPathAttribute(string _filePath)
    {
        filePath = _filePath;
    }
}

接下来就是正式的代码了:

public class EncryptTest : MonoBehaviour {

    // 游戏数据保存容器
    static List<Character> characters = new List<Character>();

	// Use this for initialization
	void Start ()
    {
        ParserFromTextFile(characters);
        foreach(var v in characters)
        {
            Debug.Log(v.ToString());
        }
    }

    // 从文件中解析出文件,并加入List中
    public static void ParserFromTextFile<T>(List<T> list, bool bRefResource = false)
    {
        // 获取路径
        string file = ((MyDataPathAttribute)Attribute.GetCustomAttribute(typeof(T), typeof(MyDataPathAttribute))).filePath;
        Debug.Log(file);

        // 获取文件内容
        string asset = null;
        if (bRefResource)
        {
            // 读取文本资源
            // 类似,可以以Resources.LoadAll(path, typeof(Texture2D))的方式读取Resources路径下的所有图片
//以下是Resources.Load读取的路径,csv和txt文件都是支持的,记得不要写后缀名,文件是放在Resources文件夹下的
//[MyDataPath("Script/Encrypt/character")]   
            asset = ((TextAsset)Resources.Load(file, typeof(TextAsset))).text;
        }
        else
        {
            // 使用C#的方法读取数据
            asset = File.ReadAllText(Application.dataPath + file);
        }

        // 解析文本内容
        StringReader reader = null;
        try
        {
            bool isHeadLine = true;
            string[] headLine = null;
            string stext = string.Empty;
            reader = new StringReader(asset);

            // 每当读取到一行时,进行处理
            while((stext = reader.ReadLine())!=null)
            {
                if (isHeadLine)
                {
                    // 第一行组成头部
                    headLine = stext.Split(',');
                    isHeadLine = false;
                }
                else
                {
                    // 余下的是数据
                    string[] data = stext.Split(',');
                    list.Add(CreateDataModule<T>(new List<string>(headLine), data));
                }
            }
        }
        catch(Exception e)
        {
            Debug.Log("file:" + file + ", message:" + e.Message);
        }
        finally
        {
            if (reader != null)
                reader.Close();
        }
    }

    // 运用反射,创建数据对应的类
    static T CreateDataModule<T>(List<string> headLine, string[] data)
    {
        // 因为T是泛型,所以无法使用new的方式创建
        T result = Activator.CreateInstance<T>();

        // 运用反射获取所有的字段
        FieldInfo[] fis = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Instance);
        foreach(FieldInfo fi in fis)
        {
            // 使用linq判断该字段是否存在
            string column = headLine.Where(tempstr => tempstr == fi.Name).FirstOrDefault();

            if(!string.IsNullOrEmpty(column))
            {
                // 存在的情况获取值
                string baseValue = data[headLine.IndexOf(column)];

                // 判断字段类型
                object setValueObj = null;
                Type setValueType = fi.FieldType;
                if(setValueType.Equals(typeof(int)))
                {
                    setValueObj = string.IsNullOrEmpty(baseValue.Trim()) ?  0 : Convert.ToInt32(baseValue);
                }
                else if(setValueType.Equals(typeof(string)))
                {
                    setValueObj = baseValue;
                }
                else
                {
                    Debug.LogError("暂时不支持该类型的转换");
                }

                // 赋值,相当于result调用fi方法赋予setValueObj的值
                fi.SetValue(result, setValueObj);
            }
        }
        return result;
    }
}

运用到了反射和linq,一开始看的时候我也是一脸懵逼,不过这些方法确实很有用,有空的时候需要深入研究一下。




  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值