赞
踩
定义:内存中的数据模型与存储模型的相互转化。
类比:将游戏数据存储到硬盘,从硬盘中读取游戏数据。
定义:JavaScript对象简谱,一种全国通用的轻量级的数据交换格式。主要在网络通信中传输数据,或本地数据的存储与读取。
特点:纯文本,层级结构,都具有描述性,键值对存储。
基本语法演示:
//大括号包裹的代表一个类
{
"name" : "Shawn",
"age" : 18,
"sex" : true,
"height" : 1.8,
//中括号代表数组
"Students" : [{"name" : "小红","sex" : false},
{"name" : "小名","sex" : false}],
"home":{"address" : "成都","street" : "春熙路"},
"son" : null
}
Excel表转Json:
访问网址:https://www.bejson.com/json/col2json
//存储字符串到指定路径文件中
//Param1:路径(可读写文件夹)
//Param2:文本内容
File.WriteAllText(Application.persistentDataPath + ”Test.json“,"hhhhhh");
//从指定路径中读取字符串
string str = File.ReadAllText(Application.persistentDataPath + "Test.json");
//将类对象序列化为Json字符串
Student s = new Student();
string str = JsonUtility.ToJson(s);
反序列化:
//读取文件中的Json字符串并将其转换为类对象
类名 变量 = JsonUtility.FromJson<类名>(jsonStr);
[System.Serializable]
[SerializeField]
定义:第三方库,由C#编写,体积小速度快易于使用。
使用步骤:
Student t = new Student();
//序列化(引入命名空间)
string jsonStr = JsonMapper.ToJson(t);
File.WriteAllText(Application.persistentDataPath + ”Test.json“,jsonStr);
反序列化:
jsonStr = File.WriteAllText(Application.persistentDataPath + ”Test.json“);
//反序列化
JsonData data = JsonMapper.ToObject(jsonStr);
//需要用索引器去访问对象内容
data["name"];
//也可以通过泛型直接返回对象
Student s = JsonMapper.ToObject<Student>(jsonStr);
//LitJson可以直接读取数组,字典类型
Student[] stus = JsonMapper.ToObject<Student[]>(jsonStr);
List<Student> stus1 = JsonMapper.ToObject<List<Student>>();
Dictionary<string,int> dic = JsonMapper.ToObject<Dictionary<string,int>>(jsonStr);
LitJson
命名空间。JsonUtility与LitJson对比:
相同点:
不同点:
/// <summary> /// 序列化和反序列化Json时 使用的是哪种方案 /// </summary> public enum JsonType { JsonUtlity, LitJson, } /// <summary> /// Json数据管理类 主要用于进行 Json的序列化存储到硬盘 和 反序列化从硬盘中读取到内存中 /// </summary> public class JsonMgr { private static JsonMgr instance = new JsonMgr(); public static JsonMgr Instance => instance; private JsonMgr() { } //存储Json数据 序列化 public void SaveData(object data, string fileName, JsonType type = JsonType.LitJson) { //确定存储路径 string path = Application.persistentDataPath + "/" + fileName + ".json"; //序列化 得到Json字符串 string jsonStr = ""; switch (type) { case JsonType.JsonUtlity: jsonStr = JsonUtility.ToJson(data); break; case JsonType.LitJson: jsonStr = JsonMapper.ToJson(data); break; } //把序列化的Json字符串 存储到指定路径的文件中 File.WriteAllText(path, jsonStr); } //读取指定文件中的 Json数据 反序列化 public T LoadData<T>(string fileName, JsonType type = JsonType.LitJson) where T : new() { //确定从哪个路径读取 //首先先判断 默认数据文件夹中是否有我们想要的数据 如果有 就从中获取 string path = Application.streamingAssetsPath + "/" + fileName + ".json"; //先判断 是否存在这个文件 //如果不存在默认文件 就从 读写文件夹中去寻找 if(!File.Exists(path)) path = Application.persistentDataPath + "/" + fileName + ".json"; //如果读写文件夹中都还没有 那就返回一个默认对象 if (!File.Exists(path)) return new T(); //进行反序列化 string jsonStr = File.ReadAllText(path); //数据对象 T data = default(T); switch (type) { case JsonType.JsonUtlity: data = JsonUtility.FromJson<T>(jsonStr); break; case JsonType.LitJson: data = JsonMapper.ToObject<T>(jsonStr); break; } //把对象返回出去 return data; } }
写在前面:C#变量的本质即为二进制。二进制文件读写的本质即为 将各类型变量转换为字节数组,将其直接存储到文件中,这样的作法不仅可以节约存储空间,提升效率,也可以提高安全性。
各类型数据与二进制相互转化:
//将各类型转字节
byte[] bytes = BitConverter.GetBytes(256);
print(bytes[0]);//0
print(bytes[1]);//1(第二位的1代表二进制八位,即十进制的256)
//将字节数组转换为其他类型
//param2:从第几个索引开始
int i = BitConverter.ToInt32(bytes,0)
//以指定编码格式转换字节数组
byte[] bytes = Encoding.UTF8.GetBytes("我是猪");
//以指定编码格式转换其他类型
string s = Encoding.UTF8.GetString(bytes);
API简介:
//判断文件是否存在 //Param:文件路径 bool isExist = File.Exists(Application.dataPath + "/data.json"); //创建文件 FileStream fs = File.Create(Application.dataPath + "/data.json"); //写入文件 byte[] bytes = BitConverter.GetBytes(999); File.WriteAllBytes(Application.dataPath + "/data.json",bytes); //写入字符串数组文件(自动空行) string[] strs = new string[]("123","我是猪"); File.WriteAllLines(Application.dataPath + "/data.json",strs); //将指定字符串存入指定路径(支持转义字符) File.WriteAllText(Application.dataPath + "/data.json","哈哈哈哈\n嘿嘿嘿"); //读取文件(类比上述API,将Write改写为Read) //删除文件 File.Delete(Application.dataPath + "/data.json"); //复制文件 //Param1:源文件 //Param2:目标文件 //Param3:如果已存在是否要覆盖原文件 File.Copy(Application.dataPath + "/data.json",Application.dataPath + "/data.guan",true); //文件替换 //Param3:备份文件路径 File.Replace(Application.dataPath + "/data.json",Application.dataPath + "/data.guan",Application.dataPath + "/data备份.txt"); //打开文件并写入或读取 //Param2:文件模式,如果没有自动创建 //Param3:访问模式,只读只写 FileStream fs = File.Open(Application.dataPath + "/data.json",FileMode.OpenOrCreate,FileAccess.ReadWrite);
//打开或创建文件 FileStream fs = new FileStream(Application.dataPath + "/data.json",FileMode.CreateOrCreate,FileAccess.ReadWrite); //文本字节长度 print(fs.Length); //将字节写入文件,写入后,一定要执行一次 fs.Flush(); //关闭流,文件读写完毕执行 fs.Close(); //缓存资源的销毁回收 fs.Dispose(); //写入字节 FileStream fs = new FileStream(Application.persistentDataPath + "/Lesson.txt",FileMode.OpenOrCreate,FileAccess.Write); byte[] test = new byte[1024]; byte[] bytes = BitConverter.GetBytes(999); //Param2:开始字节索引 //Param3:写入多少字节 fs.Write(bytes,0,bytes.Length); //写入字符串时,先写入长度 bytes = Encoding.UTF8.GetBytes("猪猪猪猪"); fs.Write(BitConverter.GetBytes(bytes.Length),0,4); fs.Write(bytes,0,bytes.Length); fs.Flush(); fs.Dispose(); //====================一个一个读取======================= //读取字节 FileStream fs2 = File.Open(Application.persistentDataPath + "/Lesson.txt",FileMode.Open,FileAccess.Read); //挨个读取字节数组 byte[] bytes2 = new byte[4]; int index = fs2.Read(bytes2,0,bytes.Length); int i = BitConverter.ToInt32(bytes2,0); print("取出来的第一个整数" + i); print("索引下标" + index); //读取字符串 index = fs2.Read(bytes2,0,4); int length = BitConverter.ToInt32(bytes2,0); //重新声明一个字节数组 bytes2 = new byte[length]; index = fs.Read(bytes2,0,length); print(Encoding.UTF8.GetString(bytes2)); fs.Dispose(); //====================一次性读取======================== FileStream fs3 = File.Open(Application.persistentDataPath + "/Lesson.txt",FileMode.Open,FileAccess.Read); byte[] bytes3 = new byte[fs3.Length]; fs3.Read(bytes3,0,(int)fs3.Length); fs3.Dispose(); print(BitConverter.ToInt32(bytes3,0)); //得出字符串长度 int length3 = BitConverter.ToInt32(bytes3,4); //得到字符串 print(Encoding.UTF8.GetString(bytes3,8,length3)); //===============通过using改进IO=================== using(FileStream fs3 = File.Open(Application.persistentDataPath + "/Lesson.txt",FileMode.Open,FileAccess.Read)) { byte[] bytes3 = new byte[fs3.Length]; fs3.Read(bytes3,0,(int)fs3.Length); fs3.Dispose(); print(BitConverter.ToInt32(bytes3,0)); //得出字符串长度 int length3 = BitConverter.ToInt32(bytes3,4); //得到字符串 print(Encoding.UTF8.GetString(bytes3,8,length3)); }
//判断文件夹是否存在 Directory.Exists(Application.dataPath + "/test"); //创建文件夹并返回 DirectoryInfo dirInfo = Directory.CreateDirectory(Application.dataPath + "/test"); //删除文件夹 //Param2:是否删除非空目录 Directory.Delete(Application.dataPath + "/test",true); //得到指定路径下的所有文件夹名 string[] strs = Directory.GetDirectories(Application.dataPath); //得到指定路径下所有文件名 strs = Directory.GetFiles(Application.dataPath); //移动文件夹 Directory.Move(Application.dataPath + "/test",Application.dataPath + "/123"); //===============DirectoryInfo类================== //目录信息类DirectoryInfo //文件夹的全路径 dirInfo.FullName; //文件夹名 dirInfo.Name; //上级文件夹信息 dirInfo = Directory.GetParent(Application.dataPath + "/test") //查找子文件夹以及文件信息 DirectoryInfo[] dirInfos = dirInfo.GetDirectories(); FileInfo[] fileInfos = dirInfo.GetFiles();
补充知识1:Unity编辑器添加选项入口:
//必须为静态方法,通过类名点方式调用
//必须存在两个或以上斜杠
//这个类可以用在任何类中
[MenuItem("GameTool/Test/GenerateExcelInfo")]
private static void Test(){
Debug.Log("测试");
}
补充知识2:刷新Project窗口内容:
AssetDatabase.Refresh();
补充知识3:Editor文件夹
项目打包时,该文件夹下的文件无法打包。通常可以把编辑器相关代码放置其中。
导入Excel的Dll文件。
打开Excel表:
[MenuItem("GameTool/OpenExcel")] private static void OpenExcel() { //文件流打开Excel using(FileStream fs = File.Open(Application.dataPath + "/ArtRes/Excel/PlayerInfo.xlsx",FileMode.Open,FileAccess.Read)){ //通过我们文件流获取Excel IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(fs); //将表中数据转换为DataSet数据类型,方便获取其中内容 DataSet result = excelReader.AsDataSet(); //得到Excel文件中所有信息 for (int i = 0;i < result.Tables.Count;i++) { print(result.Tables[i].TableName);//表名 print(result.Tables[i].Rows.Count);//行数 print(result.Tables[i].Columns.Count);//列数 } fs.Close(); } }
获取Excel表中单元格的信息:
[MenuItem("GameTool/读取具体信息")] private static void ReadExcel() { using(FileStream fs = File.Open(Application.dataPath + "/ArtRes/Excel/PlayerInfo.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]; //得到某一个单元格的信息 string ans = row[1].ToString(); //遍历所有行的数据 for (int j = 0;j < table.Rows.Count;j++){ row = table.Rows[j]; //得到每一个单元格的内容信息 for (int k = 0;k < table.Columns.Count;k++){ print(row[k].ToString()); } } } } }
需求分析:通过一张Excel表格生成以下信息:
(放入Editor下,无需打包)
public class ExcelTool { //文件目录中Excel的路径 public static string EXCEL_PATH = Application.dataPath + "/ArtRes/Excel/"; //生成的数据结构类的路径 public static string DATA_CLASS_PATH = Application.dataPath + "/Scripts/ExcelData/DataClass/"; //生成的容器类的路径 public static string DATA_CONTAINER_PATH = Application.dataPath + "/Scripts/ExcelData/DataContainer/"; //生成的二进制文件路径 public static string DATA_BINARY_PATH = Application.streamingAssetsPath + "/Binary/"; //在编辑器中添加按钮 [MenuItem("GameTool/GenerateExcel")] private static void GenerateExcelInfo() { //得到指定路径下所有文件信息(Excel表) FileInfo[] infos = Directory.CreateDirectory(EXCEL_PATH).GetFiles();; //数据表容器 DataTableCollection tableCollection; foreach(FileInfo info in infos) { //处理excel文件 if (info.Extension != ".xlsx" && info.Extension != ".xls") continue; //使用流的相关知识获取表内数据 using(FileStream fs = info.Open(FileMode.Open,FileAccess.Read)) { IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(fs); tableCollection = excelReader.AsDataSet().Tables; fs.Close(); } //得到每一张表 foreach(DataTable table in tableCollection) { //生成数据结构类 GenerateExcelDataClass(table); //生成容器类 GenerateExcelContainer(table); //生成二进制数据 GenerateExcelBinary(table); } } } }
private static void GenerateExcelDataClass(DataTable table) { //字段名字 DataRow rowName = GetRowInfo(table,0); //字段类型 DataRow rowType = GetRowInfo(table,1); if (!Directory.Exists(DATA_CLASS_PATH)) Directory.CreateDirectory(DATA_CLASS_PATH); //字符串拼接生成代码 string code = "public class " + table.TableName + "\n{\n"; //拼接变量 for (int i = 0;i < table.Columns.Count;i++) { code += " public " + rowType[i].ToString() + " " + rowName[i].ToString() + ";\n"; } code += "}"; File.WriteAllText(DATA_CLASS_PATH + table.TableName + ".cs", code); //刷新Projects窗口 AssetDatabase.Refresh(); } //获得指定行所在行信息 //获得变量名所在行信息 private static DataRow GetRowInfo(DataTable table,int row) { return table.Rows[row]; }
private static void GenerateExcelContainer(DataTable table) { int keyIndex = GetKeyIndex(table); DataRow rowType = GetRowInfo(table,1); //没有路径则创建路径 if (!Directory.Exists(DATA_CONTAINER_PATH)) Directory.CreateDirectory(DATA_CONTAINER_PATH); //字符串拼接生成类 string code = "using System.Collections.Generic;\n"; code += "public class " + table.TableName + "Container" + "\n{\n"; code += " public Dictionary<" + rowType[keyIndex].ToString() + ", " + table.TableName + "> dataDic = new Dictionary<" + rowType[keyIndex].ToString() + ", " + table.TableName + ">();\n"; code += "}"; File.WriteAllText(Data_CONTAINER_PATH + table.TableName + "Container.cs", code); AssetDatabase.Refresh(); } //找到主键所在的索引 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 default(int); }
(放在StreamingAssets包中,打包出去也要读取数据(只读))
private static void GenerateExcelBinary(DataTable table) { //判断路径下是否存在文件夹 if (!Directory.Exists(DATA_BINARY_PATH)) Directory.CreateDirectory(DATA_BINARY_PATH); //创建一个二进制文件进行写入 using(FileStream fs = new FileStream(DATA_BINARY_PATH + table.TableName + ".shawn",FileMode.OpenOrCreate,FileAccess.Write)) { //1.优先存储我们要写多少行 fs.Write(BitConverter.GetBytes(table.Rows.Count - 4),0,4); //2.存储主键的变量名(id) string keyName = GetRowInfo(table,0)[GetKeyIndex(table)].ToString(); byte[] bytes = Encoding.UTF8.GetBytes(keyName); //存储字符串字节数组的长度 fs.Write(BitConverter.GetBytes(bytes.Length),0,4); //存储字符串字节数组 fs.Write(bytes,0,bytes.Length); //数据开始索引可定义为全局变量,后续可直接修改变量 DataRow row; //得到类型 DataRow rowType = GetRowInfo(table,1); 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(int.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(); }
概念:PlayerPrefs是可以用于读取玩家数据的公共类。
存储相关:
//存储三种数据类型
PlayerPrefs.SetInt("Age",18);
PlayerPrefs.SetFloat("Height",177.5f);
PlayerPrefs.SetString("Name","Shawn");
//调用Save会把数据存入硬盘
PlayerPrefs.Save();
读取相关:
//运行时,不需要Save也能读取到
string name = PlayerPrefs.GetString("Name");
//如果找不到对应值,函数会返回第二个参数
int age = PlayerPrefs.GetInt("age",100);
删除相关:
//删除指定键
PlayerPrefs.DeleteKey("age");
//删除所有信息
PlayerPrefs.DeleteAll();
Windows:
存储路径:HKCU\Software\[公司名称]\[产品名称] 下的注册表中
。
打开方式:
Android:
存储路径:/data/data/包名/shared_prefs/pkg-name.xml
IOS:
存储路径:/Libraray/Preferences/[应用ID].plist
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。