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

来源:互联网 发布:知困然后能自强也 编辑:程序博客网 时间:2024/04/30 09:57

版本:unity 5.4.1  语言:C#

 

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

 

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

//character.csvid,name,maxHp,atk,def,spd1,Ex,100,10,5,72,pop,200,5,5,53,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 initializationvoid 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,一开始看的时候我也是一脸懵逼,不过这些方法确实很有用,有空的时候需要深入研究一下。




0 0
原创粉丝点击