【Unity数据交互】二进制私

news2024/10/6 2:21:20

在这里插入图片描述


👨‍💻个人主页:@元宇宙-秩沅

👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅!

👨‍💻 本文由 秩沅 原创

👨‍💻 专栏交流🧧
🟥Unity100个实战基础✨🎁
🟦 Unity100个精华一记✨🎁
🟩 Unity50个demo案例教程✨🎁
🟨 Unity100个精华细节BUG✨🎁

在这里插入图片描述

在这里插入图片描述


文章目录

    • 前言
    • 🎶(==1==) 数据相互转换
    • 🎶(==2==) 文件操作
    • 🎶(==3==) 文件夹操作
    • 🎶(==4==) 序列化
    • 🎶(==5==) 反序列化
    • 🎶(==6==)二进制加密
    • 🎶(==7==)Unity中使用Ecxel
      • Excel的使用基础
      • Excel的实践
      • ExcelTool(读取Excel数据生成数据结构、容器、二进制文件)
    • 🎶(==8==) BinaryData管理器
    • 🅰️系统路线学习点击跳转


前言

有符号 sbyte int short long
无符号 byte uint ushort ulong
浮点 float double decimal
特殊 bool char string

变量的本质是2进制,内存中以字节的形式存储,sizeof方法可以看到常用变量类型占用的字节空间长度

sizeof(sbyte)
sizeof(long) …

  • 节约存储空间,提升效率
  • 提升安全性

🎶(1 数据相互转换


  • 在Unity中各类型数据和字节数据相互转换

  • 1.将各类型转字节

byte[] bytes = BitConverter.GetBytes(256);
  • 2.字节数组转各类型
int i = BitConverter.ToInt32(bytes, 0);

为保证编码的正确性,编码要规范化、标准化,即需有标准的编码格式。

在C#中有一个专门的编码格式类 来帮助我们将字符串和字节数组进行转换

游戏开发中常用编码格式 UTF-8
中文相关编码格式 GBK
英文相关编码格式 ASCII

  • 1.将字符串以指定编码格式转字节
byte[] bytes = Encoding.UTF8.GetBytes("你好");
  • 2.字节数组以指定编码格式转字符串
string str = Encoding.UTF8.GetString(bytes);

🎶(2 文件操作


命名空间: System.IO

  • 1.判断文件是否存在
     if(File.Exists(Application.dataPath + "/Text"))
        {
           //存在
        }
     
  • 2.创建文件
FileStream fstream = File.Create(Application.dataPath + "/text");

  • 3.写入文件
     //字节数组 写入到指定路径的文件中
 byte[] bytes = BitConverter.GetBytes(100);
 File.WriteAllBytes(Application.dataPath + "/text", bytes);
     //string数组内容 一行行写入到指定路径中
string[] strs = new string[] { "姓名", "你好", "1", "23"};
File.WriteAllLines(Application.dataPath + "/text", strs);
     //字符串写入指定路径
File.WriteAllText(Application.dataPath + "/text", "xahhll");
  • 4.读取文件
        //读取字节数据
 bytes = File.ReadAllBytes(Application.dataPath + "/text");
 print(BitConverter.ToInt32(bytes, 0));
        //读取所有行信息
strs = File.ReadAllLines(Application.dataPath + "/text");
        for (int i = 0; i < strs.Length; i++)
        {
            print(strs[i]);
        }
        //读取所有文本信息
print(File.ReadAllText(Application.dataPath + "/text"));
  • 5.删除文件
  File.Delete(Application.dataPath + "/text");//文件前提是关闭的
  • 6.复制文件
参数一:现有文件 需要是流关闭状态
参数二:目标文件
        File.Copy(Application.dataPath + "/text", Application.dataPath + "/text2", true);
  • 7.文件替换
        //参数一:用来替换的路径
        //参数二:被替换的路径
        //参数三:备份路径
 File.Replace(Application.dataPath + "/text", 
 Application.dataPath + "/text2", Application.dataPath + "/备份text");

  • 8.以流的形式 打开文件并写入或读取

//参数一:路径
//参数二:打开模式
//参数三:访问模式
FileStream fs = File.Open(Application.dataPath + "/text", 
FileMode.OpenOrCreate, FileAccess.ReadWrite);
      

🎶(3 文件夹操作


命名空间:using System.IO
作用:增删查改文件夹

  • 1.判断文件夹是否存在
if( Directory.Exists(Application.dataPath + "/文件夹名"))
{
    print("存在");
}
  • 2.创建文件夹
DirectoryInfo info = Directory.CreateDirectory(Application.dataPath + "/文件夹名");
  • 3.删除文件夹
//参数一:路径
//参数二:true,将删除整个目录,false,仅当该目录为空时才删除
Directory.Delete(Application.dataPath + "/文件夹名");
  • 4.查找文件夹和文件
//得到所有文件夹名
string[] strs = Directory.GetDirectories(Application.dataPath);
for (int i = 0; i < strs.Length; i++)
{
    print(strs[i]);
}
//得到所有文件名
strs = Directory.GetFiles(Application.dataPath);
for (int i = 0; i < strs.Length; i++)
{
    print(strs[i]);
}

  • 5.移动文件夹
//移动会把文件夹中的所有内容一起移到新的路径
Directory.Move(Application.dataPath + "/文件夹名", Application.dataPath + "/路径");//该路径下面需为空
  • 6.创建文件夹方法的返回值
DirectoryInfo Info = Directory.CreateDirectory(Application.dataPath + "/文件夹名");
//全路径
print(Info .FullName);
//文件名
print(Info .Name);
  • 7.查找上级文件夹信息
Info = Directory.GetParent(Application.dataPath + "/文件夹名");
//全路径
print(Info .FullName);
//文件名
print(Info .Name);
  • 8.得到所有子文件夹的目录信息
DirectoryInfo[] dInfos = Info.GetDirectories();
FileInfo[] fInfos = dInfo.GetFiles();
for (int i = 0; i < fInfos.Length; i++)
{
    print("**************");
    print(fInfos[i].Name);//文件名
    print(fInfos[i].FullName);//路径
    print(fInfos[i].Length);//字节长度
    print(fInfos[i].Extension);//后缀名
}


🎶(4 序列化


序列化类对象

  • 1.第一步申明类对象

注意:如果要使用C#自带的序列化2进制方法
申明类时需要添加[System.Serializable]特性

[System.Serializable]
public class Person
{
    public int age = 1;
    public string name = "唐老狮";
    public int[] ints = new int[] { 1, 2, 3, 4, 5 };
    public List<int> list = new List<int>() { 1, 2, 3, 4 };
    public Dictionary<int, string> dic = new Dictionary<int, string>() { { 1,"123"},{ 2,"1223"},{ 3,"435345" } };
    public StructTest st = new StructTest(2, "123");//结构体
    public ClssTest ct = new ClssTest();//类
}

  • 第二步—将对象进行2进制序列化

方法一:使用内存流得到2进制字节数组
主要用于得到字节数组 可以用于网络传输
1.内存流对象
类名:MemoryStream
命名空间:System.IO
2.2进制格式化对象
类名:BinaryFormatter
命名空间:System.Runtime.Serialization.Formatters.Binary、

  Person p = new Person();        
        //主要方法:序列化方法 Serialize
        using (MemoryStream ms = new MemoryStream())
        {
            //2进制格式化程序
            BinaryFormatter bf = new BinaryFormatter();
            //序列化对象 生成2进制字节数组 写入到内存流当中
            bf.Serialize(ms, p);
            //得到对象的2进制字节数组
            byte[] bytes = ms.GetBuffer();
            //存储字节
            File.WriteAllBytes(Application.dataPath + "/文件", bytes);
            //关闭内存流
            ms.Close();
        }

方法二:使用文件流进行存储
主要用于存储到文件中

  Person p = new Person();       
        using (FileStream fs = new FileStream(Application.dataPath + "/文件名", FileMode.OpenOrCreate, FileAccess.Write))
        {
            //2进制格式化程序
            BinaryFormatter bf = new BinaryFormatter();
            //序列化对象 生成2进制字节数组 写入到内存流当中
            bf.Serialize(fs, p);
            fs.Flush();
            fs.Close();
        }
    }
}





🎶(5 反序列化


  • 1.反序列化文件中数据

主要类
FileStream文件流类
BinaryFormatter 2进制格式化类
主要方法
Deserizlize
通过文件流打开指定的2进制数据文件

     using (FileStream fs = File.Open(Application.dataPath + "/文件名", FileMode.Open, FileAccess.Read))
        {
            //申明一个 2进制格式化类
            BinaryFormatter bf = new BinaryFormatter();
            //反序列化
            Person p = bf.Deserialize(fs) as Person;

            fs.Close();
        }
  • 2.反序列化网络传输过来的2进制数据

主要类
MemoryStream内存流类
BinaryFormatter 2进制格式化类
主要方法
Deserizlize
目前没有网络传输 我们还是直接从文件中获取

  byte[] bytes = File.ReadAllBytes(Application.dataPath + "/文件名");
        //申明内存流对象 一开始就把字节数组传输进去
        using (MemoryStream ms = new MemoryStream(bytes))
        {
            //申明一个 2进制格式化类
            BinaryFormatter bf = new BinaryFormatter();
            //反序列化
            Person p = bf.Deserialize(ms) as Person;
            ms.Close();
        }

🎶(6二进制加密


  • 1,何时加密?何时解密?

当我们将类对象转换为2进制数据时进行加密
当我们将2进制数据转换为类对象时进行解密

  • 2.常用加密算法

MD5算法
SHA1算法
HMAC算法
AES/DES/3DES算法
等等等,ye 有很多的别人写好的第三发加密算法库
可以直接获取用于在程序中对数据进行加密

  • 3.简单的异或加密和解密
       Person p = new Person();
        byte key = 199;
        using (MemoryStream ms = new MemoryStream())
        {
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(ms, p);
            byte[] bytes = ms.GetBuffer();
            //异或加密
            for (int i = 0; i < bytes.Length; i++)
            {
                bytes[i] ^= key;
            }
            File.WriteAllBytes(Application.dataPath + "/文件夹名", bytes);
        }
        //解密
        byte[] bytes2 = File.ReadAllBytes(Application.dataPath + "/文件夹名");
        for (int i = 0; i < bytes2.Length; i++)
        {
            bytes2[i] ^= key;
        }
        using (MemoryStream ms = new MemoryStream(bytes2))
        {
            BinaryFormatter bf = new BinaryFormatter();
            Person p2 = bf.Deserialize(ms) as Person;
            ms.Close();
        }

🎶(7Unity中使用Ecxel


  • 导入官方提供的Excel相关DLL文件,在Editor文件夹下
    在这里插入图片描述

Excel的使用基础

  • 1.打开Excel表

主要知识点:
1.FileStream读取文件流
2.IExcelDataReader类,从流中读取Excel数据
3.DataSet 数据集合类 将Excel数据转存进其中方便读取

 [MenuItem("GameTool/打开Excel表")]
 private static void OpenExcel()
 {
     using (FileStream fs = File.Open(Application.dataPath + "/文件夹/Excel表明.xlsx", FileMode.Open, FileAccess.Read ))
     {
         //通过我们的文件流获取Excel数据
         IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(fs);
         //将excel表中的数据转换为DataSet数据类型 方便我们 获取其中的内容
         DataSet result = excelReader.AsDataSet();
         //得到Excel文件中的所有表信息
         for (int i = 0; i < result.Tables.Count; i++)
         {
             Debug.Log("表名:" + result.Tables[i].TableName);
             Debug.Log("行数:" + result.Tables[i].Rows.Count);
             Debug.Log("列数:" + result.Tables[i].Columns.Count);
         }
         fs.Close();
     }
 }
  • 2.获取Excel表中单元格的信息

主要知识点:
1.FileStream读取文件流
2.IExcelDataReader类,从流中读取Excel数据
3.DataSet 数据集合类 将Excel数据转存进其中方便读取
4.DataTable 数据表类 表示Excel文件中的一个表
5.DataRow 数据行类 表示某张表中的一行数据

[MenuItem("GameTool/读取Excel里的具体信息")]
 private static void ReadExcel()
 {
     using (FileStream fs = File.Open(Application.dataPath + "/文件夹/Excel表明.xlsx", FileMode.Open, FileAccess.Read))
     {
         IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(fs);
         DataSet result = excelReader.AsDataSet();
         for (int i = 0; i < result.Tables.Count; i++)
         {
             //得到其中一张表的具体数据
             DataTable table = result.Tables[i];
             //得到其中一行的数据
             //DataRow row = table.Rows[0];
             //得到行中某一列的信息
             //Debug.Log(row[1].ToString());
             DataRow row;
             for (int j = 0; j < table.Rows.Count; j++)
             {
                 //得到每一行的信息
                 row = table.Rows[j];
                 Debug.Log("*********新的一行************");
                 for (int k = 0; k < table.Columns.Count; k++)
                 {
                     Debug.Log(row[k].ToString());
                 }
             }
         }
         fs.Close();
     }
 }
  • 3.获取Excel表中信息对于我们的意义?

我们可以根据表中数据来动态的生成相关数据
1.数据结构类
2.容器类
3.2进制数据

为什么不直接读取Excel表而要把它转成2进制数据
1.提升读取效率
2.提升数据安全性

Excel的实践

  • 1.自定义Excel表的规则
    第一行:字段
    第二行:数据类型
    第三行:主键
    第四行:注释
    之后:数据
    (可用字典的形式存储<key,数据容器>)
    在这里插入图片描述
  • 我们想通过Ecxel表中的内容生成数据结构,生成容器脚本,如何实现呢
    见下文

ExcelTool(读取Excel数据生成数据结构、容器、二进制文件)

导入包
在这里插入图片描述

  • 在Assets文件夹下创建 ArtRes/Excel,然后放入编辑好的Excel文件
    在这里插入图片描述

  • 然后点击上方GenerateEXcel,即可生成
    在这里插入图片描述

在这里插入图片描述

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

public class ExcelTool
{
    /// <summary>
    /// excel文件存放的路径
    /// </summary>
    public static string EXCEL_PATH = Application.dataPath + "/ArtRes/Excel/";

    /// <summary>
    /// 数据结构类脚本存储位置路径
    /// </summary>
    public static string DATA_CLASS_PATH = Application.dataPath + "/Scripts/ExcelData/DataClass/";

    /// <summary>
    /// 容器类脚本存储位置路径
    /// </summary>
    public static string DATA_CONTAINER_PATH = Application.dataPath + "/Scripts/ExcelData/Container/";

    /// <summary>
    /// 真正内容开始的行号
    /// </summary>
    public static int BEGIN_INDEX = 4;

    [MenuItem("GameTool/GenerateExcel")]
    private static void GenerateExcelInfo()
    {
        //记在指定路径中的所有Excel文件 用于生成对应的3个文件
        DirectoryInfo dInfo = Directory.CreateDirectory(EXCEL_PATH);
        //得到指定路径中的所有文件信息 相当于就是得到所有的Excel表
        FileInfo[] files = dInfo.GetFiles();
        //数据表容器
        DataTableCollection tableConllection;
        for (int i = 0; i < files.Length; i++)
        {
            //如果不是excel文件就不要处理了
            if (files[i].Extension != ".xlsx" &&
                files[i].Extension != ".xls")
                continue;
            //打开一个Excel文件得到其中的所有表的数据
            using (FileStream fs = files[i].Open(FileMode.Open, FileAccess.Read))
            {
                IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(fs);
                tableConllection = excelReader.AsDataSet().Tables;
                fs.Close();
            }

            //遍历文件中的所有表的信息
            foreach (DataTable table in tableConllection)
            {
                //生成数据结构类
                GenerateExcelDataClass(table);
                //生成容器类
                GenerateExcelContainer(table);
                //生成2进制数据
                GenerateExcelBinary(table);
            }

        }
    }

    /// <summary>
    /// 生成Excel表对应的数据结构类
    /// </summary>
    /// <param name="table"></param>
    private static void GenerateExcelDataClass(DataTable table)
    {
        //字段名行
        DataRow rowName = GetVariableNameRow(table);//DataRow数据行
        //字段类型行
        DataRow rowType = GetVariableTypeRow(table);

        //判断路径是否存在 没有的话 就创建文件夹
        if (!Directory.Exists(DATA_CLASS_PATH))
            Directory.CreateDirectory(DATA_CLASS_PATH);
        //如果我们要生成对应的数据结构类脚本 其实就是通过代码进行字符串拼接 然后存进文件就行了
        string str = "public class " + table.TableName + "\n{\n";

        //变量进行字符串拼接
        for (int i = 0; i < table.Columns.Count; i++)
        {
            str += "    public " + rowType[i].ToString() + " " + rowName[i].ToString() + ";\n";
        }

        str += "}";

        //把拼接好的字符串存到指定文件中去
        File.WriteAllText(DATA_CLASS_PATH + table.TableName + ".cs", str);

        //刷新Project窗口
        AssetDatabase.Refresh();
    }

    /// <summary>
    /// 生成Excel表对应的数据容器类
    /// </summary>
    /// <param name="table"></param>
    private static void GenerateExcelContainer(DataTable table)
    {
        //得到主键索引
        int keyIndex = GetKeyIndex(table);
        //得到字段类型行
        DataRow rowType = GetVariableTypeRow(table);
        //没有路径创建路径
        if (!Directory.Exists(DATA_CONTAINER_PATH))
            Directory.CreateDirectory(DATA_CONTAINER_PATH);

        string str = "using System.Collections.Generic;\n";

        str += "public class " + table.TableName + "Container" + "\n{\n";

        str += "    ";
        str += "public Dictionary<" + rowType[keyIndex].ToString() + ", " + table.TableName + ">";
        str += "dataDic = new " + "Dictionary<" + rowType[keyIndex].ToString() + ", " + table.TableName + ">();\n";

        str += "}";

        File.WriteAllText(DATA_CONTAINER_PATH + table.TableName + "Container.cs", str);

        //刷新Project窗口
        AssetDatabase.Refresh();
    }


    /// <summary>
    /// 生成excel2进制数据
    /// </summary>
    /// <param name="table"></param>
    private static void GenerateExcelBinary(DataTable table)
    {
        //没有路径创建路径
        if (!Directory.Exists(BinaryDataMgr.DATA_BINARY_PATH))
            Directory.CreateDirectory(BinaryDataMgr.DATA_BINARY_PATH);

        //创建一个2进制文件进行写入
        using (FileStream fs = new FileStream(BinaryDataMgr.DATA_BINARY_PATH + table.TableName + ".tang", FileMode.OpenOrCreate, FileAccess.Write))
        {
            //存储具体的excel对应的2进制信息
            //1.先要存储我们需要写多少行的数据 方便我们读取
            //-4的原因是因为 前面4行是配置规则 并不是我们需要记录的数据内容
            fs.Write(BitConverter.GetBytes(table.Rows.Count - 4), 0, 4);
            //2.存储主键的变量名
            string keyName = GetVariableNameRow(table)[GetKeyIndex(table)].ToString();
            byte[] bytes = Encoding.UTF8.GetBytes(keyName);
            //存储字符串字节数组的长度
            fs.Write(BitConverter.GetBytes(bytes.Length), 0, 4);
            //存储字符串字节数组
            fs.Write(bytes, 0, bytes.Length);

            //遍历所有内容的行 进行2进制的写入
            DataRow row;
            //得到类型行 根据类型来决定应该如何写入数据
            DataRow rowType = GetVariableTypeRow(table);
            for (int i = BEGIN_INDEX; i < table.Rows.Count; i++)
            {
                //得到一行的数据
                row = table.Rows[i];
                for (int j = 0; j < table.Columns.Count; j++)
                {
                    switch (rowType[j].ToString())
                    {
                        case "int":
                            fs.Write(BitConverter.GetBytes(int.Parse(row[j].ToString())), 0, 4);
                            break;
                        case "float":
                            fs.Write(BitConverter.GetBytes(float.Parse(row[j].ToString())), 0, 4);
                            break;
                        case "bool":
                            fs.Write(BitConverter.GetBytes(bool.Parse(row[j].ToString())), 0, 1);
                            break;
                        case "string":
                            bytes = Encoding.UTF8.GetBytes(row[j].ToString());
                            //写入字符串字节数组的长度
                            fs.Write(BitConverter.GetBytes(bytes.Length), 0, 4);
                            //写入字符串字节数组
                            fs.Write(bytes, 0, bytes.Length);
                            break;
                    }
                }
            }

            fs.Close();
        }

        AssetDatabase.Refresh();
    }

    /// <summary>
    /// 获取变量名所在行
    /// </summary>
    /// <param name="table"></param>
    /// <returns></returns>
    private static DataRow GetVariableNameRow(DataTable table)
    {
        return table.Rows[0];
    }

    /// <summary>
    /// 获取变量类型所在行
    /// </summary>
    /// <param name="table"></param>
    /// <returns></returns>
    private static DataRow GetVariableTypeRow(DataTable table)
    {
        return table.Rows[1];
    }

    
    /// <summary>
    /// 获取主键索引
    /// </summary>
    /// <param name="table"></param>
    /// <returns></returns>
    private static int GetKeyIndex(DataTable table)
    {
        DataRow row = table.Rows[2];
        for (int i = 0; i < table.Columns.Count; i++)
        {
            if (row[i].ToString() == "key")
                return i;
        }
        return 0;
    }
}


🎶(8 BinaryData管理器


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

/// <summary>
/// 2进制数据管理器
/// </summary>
public class BinaryDataMgr
{
    /// <summary>
    /// 2进制数据存储位置路径
    /// </summary>
    public static string DATA_BINARY_PATH = Application.streamingAssetsPath + "/Binary/";

    /// <summary>
    /// 用于存储所有Excel表数据的容器
    /// </summary>
    private Dictionary<string, object> tableDic = new Dictionary<string, object>();

    /// <summary>
    /// 数据存储的位置
    /// </summary>
    private static string SAVE_PATH = Application.persistentDataPath + "/Data/";

    private static BinaryDataMgr instance = new BinaryDataMgr();
    public static BinaryDataMgr Instance => instance;

    private BinaryDataMgr()
    {
        InitData();
    }

    public void InitData()
    {
      //在此处编写初始化数据
    }

    /// <summary>
    /// 加载Excel表的2进制数据到内存中 
    /// </summary>
    /// <typeparam name="T">容器类名</typeparam>
    /// <typeparam name="K">数据结构类类名</typeparam>
    public void LoadTable<T,K>()
    {
        //读取 excel表对应的2进制文件 来进行解析
        using (FileStream fs = File.Open(DATA_BINARY_PATH + typeof(K).Name + ".tang", FileMode.Open, FileAccess.Read))
        {
            byte[] bytes = new byte[fs.Length];
            fs.Read(bytes, 0, bytes.Length);
            fs.Close();
            //用于记录当前读取了多少字节了
            int index = 0;

            //读取多少行数据
            int count = BitConverter.ToInt32(bytes, index);
            index += 4;

            //读取主键的名字
            int keyNameLength = BitConverter.ToInt32(bytes, index);
            index += 4;
            string keyName = Encoding.UTF8.GetString(bytes, index, keyNameLength);
            index += keyNameLength;

            //创建容器类对象
            Type contaninerType = typeof(T);
            object contaninerObj = Activator.CreateInstance(contaninerType);
            //得到数据结构类的Type
            Type classType = typeof(K);
            //通过反射 得到数据结构类 所有字段的信息
            FieldInfo[] infos = classType.GetFields();

            //读取每一行的信息
            for (int i = 0; i < count; i++)
            {
                //实例化一个数据结构类 对象
                object dataObj = Activator.CreateInstance(classType);
                foreach (FieldInfo info in infos)
                {
                    if( info.FieldType == typeof(int) )
                    {
                        //相当于就是把2进制数据转为int 然后赋值给了对应的字段
                        info.SetValue(dataObj, BitConverter.ToInt32(bytes, index));
                        index += 4;
                    }
                    else if (info.FieldType == typeof(float))
                    {
                        info.SetValue(dataObj, BitConverter.ToSingle(bytes, index));
                        index += 4;
                    }
                    else if (info.FieldType == typeof(bool))
                    {
                        info.SetValue(dataObj, BitConverter.ToBoolean(bytes, index));
                        index += 1;
                    }
                    else if (info.FieldType == typeof(string))
                    {
                        //读取字符串字节数组的长度
                        int length = BitConverter.ToInt32(bytes, index);
                        index += 4;
                        info.SetValue(dataObj, Encoding.UTF8.GetString(bytes, index, length));
                        index += length;
                    }
                }

                //读取完一行的数据了 应该把这个数据添加到容器对象中
                //得到容器对象中的 字典对象
                object dicObject = contaninerType.GetField("dataDic").GetValue(contaninerObj);
                //通过字典对象得到其中的 Add方法
                MethodInfo mInfo = dicObject.GetType().GetMethod("Add");
                //得到数据结构类对象中 指定主键字段的值
                object keyValue = classType.GetField(keyName).GetValue(dataObj);
                mInfo.Invoke(dicObject, new object[] { keyValue, dataObj });
            }

            //把读取完的表记录下来
            tableDic.Add(typeof(T).Name, contaninerObj);

            fs.Close();
        }
    }

    /// <summary>
    /// 得到一张表的信息
    /// </summary>
    /// <typeparam name="T">容器类名</typeparam>
    /// <returns></returns>
    public T GetTable<T>() where T:class
    {
        string tableName = typeof(T).Name;
        if (tableDic.ContainsKey(tableName))
            return tableDic[tableName] as T;
        return null;
    }

    /// <summary>
    /// 存储类对象数据
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="fileName"></param>
    public void Save(object obj, string fileName)
    {
        //先判断路径文件夹有没有
        if (!Directory.Exists(SAVE_PATH))
            Directory.CreateDirectory(SAVE_PATH);

        using (FileStream fs = new FileStream(SAVE_PATH + fileName + ".tang", FileMode.OpenOrCreate, FileAccess.Write))
        {
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(fs, obj);
            fs.Close();
        }
    }

    /// <summary>
    /// 读取2进制数据转换成对象
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="fileName"></param>
    /// <returns></returns>
    public T Load<T>(string fileName) where T:class
    {
        //如果不存在这个文件 就直接返回泛型对象的默认值
        if( !File.Exists(SAVE_PATH + fileName + ".tang") )
            return default(T);

        T obj;
        using (FileStream fs = File.Open(SAVE_PATH + fileName + ".tang", FileMode.Open, FileAccess.Read))
        {
            BinaryFormatter bf = new BinaryFormatter();
            obj = bf.Deserialize(fs) as T;
            fs.Close();
        }

        return obj;
    }
}

2.刷新Project窗口内容

因为我们用代码创建完文件后需要被刷新之后才可以看到

    //  Directory.CreateDirectory(Application.dataPath + "/测试文件夹");
      AssetDatabase.Refresh();

在这里插入图片描述

🅰️系统路线学习点击跳转


👨‍💻 Unity程序基础学习路线🧧
⭐【Unityc#专题篇】之c#进阶篇】🎁
⭐【Unityc#专题篇】之c#核心篇】🎁
⭐【Unityc#专题篇】之c#基础篇】🎁
⭐【Unity-c#专题篇】之c#入门篇】🎁
【Unityc#专题篇】—进阶章题单实践练习🎁
⭐【Unityc#专题篇】—基础章题单实践练习🎁
【Unityc#专题篇】—核心章题单实践练习🎁

你们的点赞👍 收藏⭐ 留言📝 关注✅是我持续创作,输出优质内容的最大动力!


在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1900563.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

迭代加深——AcWing 170. 加成序列

迭代加深 定义 迭代加深搜索&#xff08;Iterative Deepening Depth-First Search, IDS&#xff09;是一种结合了深度优先搜索&#xff08;DFS&#xff09;和广度优先搜索&#xff08;BFS&#xff09;特点的算法。它通过限制搜索树的深度来控制搜索范围&#xff0c;起初以较小…

【C++】开源:nlohmann/json数据解析库配置使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍nlohmann/json数据解析库配置使用。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&am…

XAML 框架横向对比

多年来&#xff0c;基于 XAML 的 UI 框架有了很大的发展。下面的图表很好地证明了这个观点。XAML UI 框架的三大巨头&#xff1a;Avalonia UI、Uno Platform 和 .NET MAUI 都支持跨平台的应用。事实上&#xff0c;除了 Avalonia UI&#xff0c;对跨平台 XAML 的需求是它们发展的…

FPGA开发笔试1

1. 流程简介 我是两天前有FPGA公司的HR来问我实习的事情&#xff0c;她当时问我距离能不能接受&#xff0c;不过确实距离有点远&#xff08;地铁通勤要将近一个半小时&#xff09;&#xff0c;然后她说给我约个时间&#xff0c;抽空做1个小时的题目&#xff08;线上做&#xf…

(数据大屏)(Hadoop)基于SSM框架的学院校友管理系统的设计与实现+文档

&#x1f497;博主介绍&#x1f497;&#xff1a;✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示&#xff1a;文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐…

控制下属绝不是拍桌子、甩脸子、摆架子,一流领导都用这3招!

控制下属绝不是拍桌子、甩脸子、摆架子&#xff0c;一流领导都用这3招&#xff01; 第一招&#xff1a;规矩严 国有国法&#xff0c;家有家规&#xff0c;公司也不例外。 下属能不能和领导齐心&#xff0c;愿不愿意共同发力&#xff0c;全看管理者如何操控。 毫无疑问的是&a…

NSSCTF-Web题目24(RCE-空格绕过、过滤绕过)

目录 [MoeCTF 2021]babyRCE 1、题目 2、知识点 3、思路 [SWPUCTF 2022 新生赛]funny_web 4、题目 5、知识点 6、思路 [MoeCTF 2021]babyRCE 1、题目 2、知识点 空格绕过、过滤绕过 3、思路 出现源码&#xff0c;进行代码审计 需要我们GET方式上传一个rce变量&#x…

程序员下班为什么不关电脑?难道在偷偷加班?!

不管是周围的程序员朋友还是网上的很多程序员朋友&#xff0c;在下班后都是习惯不关电脑的&#xff0c;关上显示器&#xff0c;拿上手机&#xff0c;快乐下班&#xff01; 那么&#xff0c;为什么程序员下班都不关电脑&#xff1f;难道他们在偷偷加班&#xff1f; 其实&#x…

从GREE格力看如何起全球商标名称!

有些主体需要走出去出口到国外&#xff0c;普推商标知产老杨看到在一些海外电商平台的出售产品&#xff0c;也会需要英文商标&#xff0c;有的会申请申请注册中英结合商标&#xff0c;在国外申请注册也是比较方便。 格力开始想用“GLEE”(快乐)这个词作为商标名称&#xff0c;但…

七人互助拼团模式:共创共赢的电商新篇章

在当今电商行业的繁荣浪潮中&#xff0c;七人互助拼团模式犹如一股清流&#xff0c;凭借其独特的激励机制与深厚的互助合作文化&#xff0c;赢得了消费者与商家的广泛赞誉。这一模式不仅重新定义了团购体验&#xff0c;更在无形中强化了社群间的联系与协作&#xff0c;共同绘制…

Nettyの参数优化简单RPC框架实现

本篇介绍Netty调优&#xff0c;在上篇聊天室的案例中进行改造&#xff0c;手写一个简单的RPC实现。 1、超时时间参数 CONNECT_TIMEOUT_MILLIS 是Netty的超时时间参数&#xff0c;属于客户端SocketChannel的参数&#xff0c;客户端连接时如果一定时间没有连接上&#xff0c;就会…

【数据结构】常见四类排序算法

1. 插入排序 1.1基本思想&#xff1a; 直接插入排序是一种简单的插入排序法&#xff0c;其基本思想是&#xff1a;把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中&#xff0c;直到所有的记录插入完为止&#xff0c;得到一个新的有序序列 。实际中我们…

Windows Server 2016 搭建 网络负载平衡 服务

网络负载平衡功能的安装 添加角色 默认不动————功能 勾选上 < 网络负载平衡 > 在工具中————打开 < 网络负载平衡管理器 > 网络负载平衡群集创建 注意 : 提前 将两台 web 站点服务器 都安装好 < 网络负载平衡功能 > 右键 选择 ————新建群集 ——…

麦蕊智数,,另外一个提供免费的股票数据API,可以通过其提供的接口获取实时和历史的股票数据。

麦蕊智数&#xff0c;&#xff0c;提供免费的股票数据API&#xff0c;可以通过其提供的接口获取实时和历史的股票数据。 API接口&#xff1a;http://api.mairui.club/hslt/new/您的licence 备用接口&#xff1a;http://api1.mairui.club/hslt/new/您的licence 请求频率&#x…

yolov5 json 和 txt数据格式关系

训练阶段 和 推理阶段数据格式转换说明 关于yolov5 数据格式一直以来都傻傻分不清楚&#xff0c;这下进行了一个梳理&#xff0c;做了笔记&#xff0c;也希望可帮助到有需要的有缘人~ 转换部分代码

使用JAR命令打包JAR文件使用Maven打包使用Gradle打包打包Spring Boot应用

本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:王文峰…

跨平台书签管理器 - Raindrop

传统的浏览器书签功能虽然方便&#xff0c;但在管理和分类上存在诸多局限。今天&#xff0c;我要向大家推荐一款功能强大的跨平台书签管理-Raindrop https://raindrop.io/ &#x1f4e2; 主要功能&#xff1a; 智能分类和标签管理 强大的搜索功能 跨平台支持 分享与协作 卡片式…

电脑f盘的数据回收站清空了能恢复吗

随着信息技术的飞速发展&#xff0c;电脑已成为我们日常生活和工作中不可或缺的设备。然而&#xff0c;数据的丢失或误删往往会给人们带来极大的困扰。尤其是当F盘的数据在回收站被清空后&#xff0c;许多人会陷入绝望&#xff0c;认为这些数据已无法挽回。但事实真的如此吗&am…

芯片基识 | 掰开揉碎讲 FIFO(同步FIFO和异步FIFO)

文章目录 一、什么是FIFO二、为什么要用FIFO三、什么时候用FIFO四、FIFO分类五、同步FIFO1. 同步FIFO电路框图2. 同步FIFO空满判断3. 同步FIFO设计代码4. 同步FIFO仿真结果 六、异步FIFO1、异步FIFO的电路框图2 、亚稳态3、打两拍4、格雷码5、如何判断异步FIFO的空满&#xff0…

Selenium的自动化测试技巧有多少?【建议收藏】

Selenium是一个用于自动化Web应用程序测试的工具。它提供了一组API&#xff0c;允许用户与Web浏览器进行交互&#xff0c;来执行各种自动化测试任务。本文将从零开始&#xff0c;详细介绍Selenium的自动化测试技巧。 第一步&#xff1a;安装Selenium 首先&#xff0c;您需要安…