【Unity數據交互】二進制私

在這里插入圖片描述


👨?💻個人主頁:@元宇宙-秩沅

👨?💻 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();        //主要方法:序列化方法 Serializeusing (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);//得到數據結構類的TypeType 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.pswp.cn/diannao/41614.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/41614.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/41614.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Bootstrap 5 小工具

Bootstrap 5 小工具 Bootstrap 5 是一個流行的前端框架,它提供了一系列的工具和組件,幫助開發者快速構建響應式和移動優先的網頁。在本文中,我們將探討 Bootstrap 5 中的一些實用小工具,這些工具可以極大地提高開發效率和用戶體驗。 1. 網格系統 Bootstrap 5 的網格系統…

Laravel 宏指令(Macro)動態添加自定義方法到Laravel的核心組件中

Laravel 宏指令&#xff08;Macro&#xff09; 在Laravel中&#xff0c;宏指令&#xff08;Macro&#xff09;是一種靈活的方式&#xff0c;允許您動態添加自定義方法到Laravel的核心組件中&#xff0c;如模型、查詢構建器、集合等&#xff0c;以便在不改變核心代碼的情況下擴展…

電腦硬盤分區的基本步驟(2個實用的硬盤分區方法)

在現代計算機中&#xff0c;硬盤分區是非常重要的一步。無論是新硬盤的初始化&#xff0c;還是重新組織現有硬盤&#xff0c;分區都是必不可少的操作。本文將詳細介紹電腦硬盤分區的基本步驟&#xff0c;幫助您更好地管理和利用硬盤空間。 文章開始&#xff0c;我們先簡單說一…

【C++】 解決 C++ 語言報錯:Invalid Conversion from ‘const char*’ to ‘char*’

文章目錄 引言 在 C 編程中&#xff0c;類型轉換錯誤&#xff08;Invalid Conversion&#xff09;是常見的編譯錯誤之一。特別是當程序試圖將一個常量字符指針&#xff08;const char*&#xff09;轉換為非常量字符指針&#xff08;char*&#xff09;時&#xff0c;會導致編譯…

Vmware環境下ESXi主機 配置上行鏈路、虛擬交換機、端口組、VMkernel網卡

一、適用場景 1、使用專業服務器跑多種不同的業務&#xff0c;每種業務可能所需運行的server環境不同&#xff0c;有的需要Linux server CentOS7/8、kali、unbuntu……有的需要windows server2008、2003、2016、2019、2022…… 2、本例采用的是VMware ESXi6.7 update 3版本&am…

力扣習題--找不同

目錄 前言 題目和解析 1、找不同 2、 思路和解析 總結 前言 本系列的所有習題均來自于力扣網站LeetBook - 力扣&#xff08;LeetCode&#xff09;全球極客摯愛的技術成長平臺 題目和解析 1、找不同 給定兩個字符串 s 和 t &#xff0c;它們只包含小寫字母。 字符串 t…

Java Maven中自動代碼檢查插件詳細介紹

文章目錄 Checkstyle主要特點使用場景配置與使用checkstyle.xmlsuppressions.xml 驗證打包時驗證執行命令驗證 Spotless配置文件內容Java配置部分POM 配置部分Markdown 配置部分Up to Date Checking執行部分 驗證打包時驗證在插件中執行命令驗證 Checkstyle Spotless 結合chec…

ABAP中BAPI_CURRENCY_CONV_TO_INTERNAL 函數的使用方法

在ABAP中&#xff0c;BAPI_CURRENCY_CONV_TO_INTERNAL 函數模塊主要用于將外部金額轉換為內部存儲格式。這對于確保金額數據在SAP系統中的一致性和準確性至關重要。以下是關于該函數模塊使用方法的詳細解釋&#xff1a; 函數模塊參數 調用 BAPI_CURRENCY_CONV_TO_INTERNAL 時…

redis學習(005 java客戶端 RedisTemplate學習)

黑馬程序員Redis入門到實戰教程&#xff0c;深度透析redis底層原理redis分布式鎖企業解決方案黑馬點評實戰項目 總時長 42:48:00 共175P 此文章包含第16p-第p23的內容 文章目錄 java客戶端jedisSpringDataRedis項目實現hash哈希操作 java客戶端 jedis 測試 ps:如果連接不上&…

vs2019 無法打開項目文件

vs2019 無法打開項目文件&#xff0c;無法找到 .NET SDK。請檢查確保已安裝此項且 global.json 中指定的版本(如有)與所安裝的版本相匹配 原因&#xff1a;缺少組件 解決方案&#xff1a;選擇需要的組件進行安裝完成

C#靜態類與非靜態類

1、靜態類 靜態類有幾個重要的特點&#xff1a; 1&#xff09;無法實例化&#xff1a;由于靜態類不能被實例化&#xff0c;因此它不會占用對象內存。 2&#xff09;靜態成員&#xff1a;靜態類只能包含靜態成員&#xff08;靜態方法、靜態屬性、靜態事件等&#xff09;。 3&am…

步進電機改伺服電機

步進電機&#xff1a; 42&#xff1a;軸徑5mm 57&#xff1a;軸徑8mm 86&#xff1a;軸徑14mm 【86CME120閉環】// 12牛米 伺服電機&#xff1a; 40&#xff1a; 60&#xff1a; 80&#xff1a; 86&#xff1a; ECMA——C 1 0910 R S 4.25A 軸徑…

評價ChatGPT與強人工智能的未來

在人工智能領域&#xff0c;ChatGPT的出現無疑是一個里程碑事件。它不僅展示了自然語言處理技術的巨大進步&#xff0c;也引發了人們對于強人工智能&#xff08;AGI&#xff09;的無限遐想。本文將從多個角度評價ChatGPT&#xff0c;并探討強人工智能距離我們還有多遠。 ChatGP…

虛擬地址和物理地址

到底什么是虛擬地址呢&#xff1f;它和物理地址的區別又在哪呢&#xff1f; 一. 虛擬地址的作用 1. 使代碼的移植性更好&#xff0c;在不同平臺進行編譯以后&#xff0c;就可以直接運行&#xff0c;因為到別的系統&#xff0c;會將你的虛擬地址轉換為物理地址&#xff0c;而使…

無人機運營合格證及無人機駕駛員合格證(AOPA)技術詳解

無人機運營合格證及無人機駕駛員合格證&#xff08;AOPA&#xff09;技術詳解如下&#xff1a; 一、無人機運營合格證 無人機運營合格證是無人機運營企業或個人必須獲得的證書&#xff0c;以確保無人機在運營過程中符合相關法規和標準。對于無人機運營合格證的具體要求和申請…

無人機人員搜救

人員搜救-水域救援 水域搜救&#xff1a;快速水面搜查 物資拋投&#xff1a;救生物資拋投 繩索牽引&#xff1a;牽引救援繩索 領航船艇&#xff1a;水面偵察領航 人員搜救 晝夜搜救&#xff0c;精準定位 水域搜救 經緯 M300 RTK 搭載禪思 H20T 能夠滿足全天候作業需求&a…

【區分vue2和vue3下的element UI Dialog 對話框組件,分別詳細介紹屬性,事件,方法如何使用,并舉例】

在 Vue 2 和 Vue 3 中&#xff0c;Element UI&#xff08;針對 Vue 2&#xff09;和 Element Plus&#xff08;針對 Vue 3&#xff09;提供了 Dialog 對話框組件&#xff0c;用于在頁面中顯示模態對話框。這兩個庫中的 Dialog 組件在屬性、事件和方法的使用上有所相似&#xff…

新手教學系列——Git Stash踩坑

在之前的文章《如何徹底避免Git代碼相互覆蓋問題》中,我曾介紹過通過規范分支合并和使用git stash來避免代碼覆蓋問題。今天,我要深入探討一下git stash的使用,并分享一些使用過程中遇到的坑,希望能幫你避免類似問題。 腳本mg.sh簡介 為了更好地管理代碼合并,我編寫了一…

gcc: 自身編譯: opt;有個變量怎么找不到?

文章目錄 makefile/configure中間awk的轉換舉例,options.h里的內容:解開疑問makefile/configure lang_opt_files=@lang_opt_files@ $(srcdir)/c-family/c.opt $(srcdir)/common.opt# All option source files ALL_OPT_FILES=$(lang_opt_files) $(extra_opt_files

linux之管道重定向

管道與重定向 一、重定向 將原輸出結果存儲到其他位置的過程 標準輸入、標準正確輸出、標準錯誤輸出 ? 進程在運行的過程中根據需要會打開多個文件&#xff0c;每打開一個文件會有一個數字標識。這個標識叫文件描述符。 進程使用文件描述符來管理打開的文件&#xff08;FD--…