IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> Unity读取写入CSV数据 -> 正文阅读

[游戏开发]Unity读取写入CSV数据

1.CSV文件对应的类:

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

public class UserAccount: GameConfigDataBase
{
    public string ID;
    public string NickName;
    public string Password;
}

  1. 读取写入数据类:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.Reflection;
using UnityEngine.UI;
using System.IO;
using System.Text;

public class GameConfigDataBase
{
    static List<string> writeDataList = new List<string>();
    //第一个sting是表名,第二个string是表的id值,GameConfigDataBase存的是每一行的数据,每一行为一个对象;
    public static Dictionary<string, Dictionary<string, GameConfigDataBase>> csvConfigData = new Dictionary<string,Dictionary<string, GameConfigDataBase>>();

    /// <summary>
    /// 读取CSV文件
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="fileName"></param>
    public static void ReadGameConfigCsv<T>(string fileName) where T : GameConfigDataBase
    {
        Dictionary<string, GameConfigDataBase> objDic = new Dictionary<string, GameConfigDataBase>();

        string filePath = Application.streamingAssetsPath + "\\" + fileName + ".csv";
        //ReadAllLines适合读取小文件
        //string[] lineArray = File.ReadAllLines(filePath);
        string[] lineArray = {};
        try
        {
            using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
            {
                //开辟内存区域 缓存读出来的文本数据 用于将来显示在控制台里
                byte[] byteArray = new byte[1024 * 1024 * 10]; //10M空间

                //开始读取数据   0表示从缓存内存的第一个字节开始  
                //count 是我们真正读取到的字节数量  比如我们在文件结尾,可能没有1M的数据给我们读
                //这个方法刚好返回的是我们从文本中读取的字节数量
                int count = fs.Read(byteArray, 0, byteArray.Length);

                //开始转码   二进制我们是无法看的  我们需要转成字符串形式
                string csvStr = Encoding.UTF8.GetString(byteArray, 0, count);
                //读取每一行的内容存入数组,数组的长度就是行数,csv每行是以\r\n换行
                lineArray = csvStr.Split('\n');
                //读取文本操作完成后。我们需要释放一切关于文件流操作申请的计算机资源,不释放的话,操作系统是不会主动回收的。我们需要自己去释放
                fs.Close();
            }
        }
        catch (Exception e)
        {
            Debug.LogException(e);
            return;
        }

        //对表字段名进行分割存入数组,第二行是表字段名,对应的T类的字段
        string[] keyArray = lineArray[2].Split(","[0]);
       
        //把csv中的数据以第三行列名为字段名,对字段进行赋值。每一行以ID列的值为key
        //还需要处理单元格中存在逗号的情况,一般是用双引号括起来,最后一行是空字符需要-1
        //外层循环为行,内存循环为列。每一行为一个对象
        for (int i = 3; i < lineArray.Length - 1; i++)
        {
            T configObj = Activator.CreateInstance<T>();   //创建对象
            //再对行进行分割
            string[] line = lineArray[i].Split(',');
            string[] newLine = SplitStrArray(line);
            string idValue = "";
            if (newLine.Length != 0)
            {
                line = newLine;
            }
            //处理一行中的每个字段,对configObj的每个字段字段进行赋值
            for (int j = 0; j < line.Length; j++)
            {
                //Trim()去掉字段前面的多余字符,否则获取不到数据
                string resStr = SetValue<T>(keyArray[j].Trim(), line[j].Trim(), configObj);

                if (resStr != "")
                {
                    idValue = resStr;
                }
            }
            //configObj对所有字段赋值后,以id的值为键,T类型的对象为值,存入到字典中
            objDic.Add(idValue, configObj);
        }
        //向字典中增加数据
        GameConfigDataBase.csvConfigData.Add(fileName, objDic);
        //Debug.Log($"objDic: {objDic.Count}, {csvConfigData.Count}");
       
    }

    /// <summary>
    /// 1.有的值中间有逗号,进行逗号分割后还需要再次进行处理。
    /// 2.处理单元格中带逗号的值,这些值是以双引号括起来的
    /// 3.判断是遇到双引号,如果发现有,则iCount进行累计,isFind为true
    /// 4.发现双引号后,将双引号中间的值存进数组,然后将这些字符串重新组合成字符串,存入要返回的list中
    /// 5.返回一个新的数组,此数组与csv表中的数据一致
    /// </summary>
    /// <param name="lineArray"></param>
    private static string[] SplitStrArray(string[] lineArray)
    {
        int iCount = 1;
        bool isFind = false;
        string[] newStrArray = { };
        List<string> tempStrList = new List<string>();
        List<string> newStrList = new List<string>();
        //引号成对出现,前面的引号是奇数个,后面是偶数个
        for (int i = 0; i < lineArray.Length; i++)
        {

            if (lineArray[i].Contains("\""))
            {
                //如果发现双引号且是奇数,则说是前面的引号
                if (iCount % 2 != 0)
                {
                    isFind = true;
                    tempStrList.Add(lineArray[i]);
                }
                else if (iCount % 2 == 0)
                {
                    如果发现双引号且是偶数,则说是后面的引号
                    tempStrList.Add(lineArray[i]);
                    isFind = false;
                    //最后以逗号分割,重新组合成新的字符串
                    string str = String.Join(",", tempStrList.ToArray());
                    //将组合后的值存入要返回的list中
                    newStrList.Add(str);
                    //清掉数组的中值
                    tempStrList.Clear();
                }
                iCount++;
            }
            else if (isFind)
            {
                //如果有引号则把双引号中间的值也存入tempStrList
                tempStrList.Add(lineArray[i]);
            }
            else
            {
                //如果当前的值不再双引号中间,则直接存入最后要返回的list中
                newStrList.Add(lineArray[i]);
            }
        }
        //如果iCount没有变,则说明不存在双引号,不需要处理
        if (iCount != 1)
        {
            newStrArray = newStrList.ToArray();
        }

        return newStrArray;
    }

    /// <summary>
    /// 通过反射对字段进行赋值
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="fieldName">字段名</param>
    /// <param name="fieldValue">字段对应的值</param>
    /// <param name="configObj">保存字段值的类对象</param>
    /// <returns></returns>
    public static string SetValue<T>(string fieldName, string fieldValue, T configObj) where T : GameConfigDataBase
    {
        string idValue = "";
        Type type = typeof(T);  //获取类型
        //遍历类的所有字段
        foreach (var Field in type.GetFields())//GetFields获取字段
        {
            //判断传入的字段名与当前反射得到的类字段名是否相同
            if (Field.Name.Equals(fieldName))
            {
                object setValue = new object();
                //判断字段类型,将值从string类型转换为跟字段相同的类型
                switch (Field.FieldType.ToString())
                {
                    case "System.Int32":
                        // 转换类型
                        setValue = int.Parse(fieldValue);
                        break;
                    case "System.Int64":
                        setValue = long.Parse(fieldValue);
                        break;
                    case "System.String":
                        setValue = fieldValue;
                        break;
                    case "System.Single":
                        try
                        {
                            setValue = float.Parse(fieldValue);
                        }
                        catch (System.Exception e)
                        {
                            setValue = 0.0f;
                        }

                        break;
                    default:
                        Debug.Log("error data type: " + Field.FieldType.ToString());
                        break;
                }
                //给类对象的字段赋值
                Field.SetValue(configObj, setValue);
                if (Field.Name == "ID")
                {
                    idValue = setValue.ToString();
                }
                //Debug.Log($"{type}.{ Field.Name} = { Field.GetValue(configObj)}");
            }
        }

        return idValue;
    }

    /// <summary>
    /// 从字典中获取数据
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="fileName"></param>
    /// <param name="key"></param>
    /// <returns></returns>
    public static T GetGameConfigCsv<T>(string fileName, string key) where T : GameConfigDataBase
    {
        T configObj = null;
        if (!csvConfigData.ContainsKey(fileName))
        {
            return configObj;
        }

        //数据在开始的时候初始化一次,当数据发生改变后,需要重新获表数据
        //考虑动态实时查询数据, 删除字典中的表,重新执行一次读取; 
        csvConfigData.Remove(fileName);
        ReadGameConfigCsv<T>(fileName);

        Dictionary<string, GameConfigDataBase> objDic = csvConfigData[fileName];
        // Debug.Log("test  (" + key + ")" + objDic.Count);
        if (objDic.ContainsKey(key))
        {
            configObj = (T)(objDic[key]);
        }

        return configObj;
    }

    /// <summary>
    /// 写数据
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="fileName">文件名</param>
    /// <param name="configObj">对应的对象实例</param>
    public static void WriteDataToCsv<T>(string fileName, T configObj) where T : GameConfigDataBase
    {
        Type typeT = typeof(T);

        /*      GetProperty是只针对属性的,需要添加{get;set;} 标识这是一个属性,
         *      如果没有添加{ get; set; }说明是一个字段,可以使用GetField
         */
        FieldInfo[] propertyInfos = configObj.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
        foreach (var Field in typeT.GetFields())
        {
            foreach (FieldInfo pItem in propertyInfos)
            {
                if (Field.Name.Equals(pItem.Name))
                {
                    object value = pItem.GetValue(configObj);
                    writeDataList.Add(value.ToString());
                }
            }
        }
        string newStr = string.Join(",", writeDataList.ToArray());
        string filePath = Application.streamingAssetsPath + "\\" + fileName + ".csv";
        //写入文件,FileMode.Append追加写入
        using (FileStream fileStream = new FileStream(filePath, FileMode.Append, FileAccess.Write))
        {
            using (TextWriter textWriter = new StreamWriter(fileStream, Encoding.UTF8))
            {
                //WriteLine方法会自动在行的尾部添加\r\n字符
                textWriter.WriteLine(newStr);
                textWriter.Close();
            }
            fileStream.Close();
        }
        writeDataList.Clear();
    }
}

3.调用:

UserAccount UserAccountInfo;
GameConfigDataBase.ReadGameConfigCsv<UserAccount>("UserAccount");
UserAccountInfo = GameConfigDataBase.GetGameConfigCsv<UserAccount>("UserAccount", "t123456");
UserAccountInfo = new UserAccount();
UserAccountInfo.ID = accountText.text;
UserAccountInfo.Password = passwordField.text;
UserAccountInfo.NickName = "test01";
GameConfigDataBase.WriteDataToCsv<UserAccount>("UserAccount", UserAccountInfo);

4.CSV文件:
在这里插入图片描述
在这里插入图片描述

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-03-06 13:29:43  更:2022-03-06 13:31:44 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 17:50:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码