Unity数据持久化4——2进制
概述











基础知识
各类型数据转字节数据





文件操作相关

文件相关




文件流相关







文件夹相关





练习题

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;public class Exercises1 : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){//Student s = new Student();//s.age = 18;//s.name = "Sunset";//s.number = 1;//s.sex = true;//s.Save("学生信息");Student s2 = Student.Load("学生信息");}// Update is called once per framevoid Update(){}
}public class Student
{public int age;public string name;public int number;public bool sex;public void Save(string fileName){Debug.Log(Application.persistentDataPath);//如果不存在指定路径 则创建一个文件夹if( !Directory.Exists(Application.persistentDataPath + "/Student")){Directory.CreateDirectory(Application.persistentDataPath + "/Student");}//新建一个指定名字的文件 并且返回 文件流 进行字节的存储using (FileStream fs = new FileStream(Application.persistentDataPath + "/Student/" + fileName + ".set", FileMode.OpenOrCreate, FileAccess.Write)){//先写 agebyte[] bytes = BitConverter.GetBytes(age);fs.Write(bytes, 0, bytes.Length);//写 name (先存这个字节的长度,再存字节内容)bytes = Encoding.UTF8.GetBytes(name);//存储字符串字节数组的长度fs.Write(BitConverter.GetBytes(bytes.Length), 0, 4);fs.Write(bytes, 0, bytes.Length);//写 numberbytes = BitConverter.GetBytes(number);fs.Write(bytes, 0, bytes.Length);//写 sexbytes = BitConverter.GetBytes(sex);fs.Write(bytes, 0, bytes.Length);//一定记住fs.Flush();fs.Dispose();}}public static Student Load(string fileName){//判断文件是否存在if (!File.Exists(Application.persistentDataPath + "/Student/" + fileName + ".set")){Debug.LogWarning("没有找到对于文件");return null;}//申明对象Student s = new Student();//加载2进制文件 进行赋值using(FileStream fs = File.Open(Application.persistentDataPath + "/Student/" + fileName + ".set", FileMode.Open, FileAccess.Read)){//把我们文件中的字节 全部读取出来byte[] bytes = new byte[fs.Length];fs.Read(bytes, 0, bytes.Length);fs.Close(); //Dispose 就可以不用调用了 因为 usin会帮我们调用一次int index = 0;//挨个读取其中的内容//先读 ages.age = BitConverter.ToInt32(bytes, index);index += 4;//读 name//先读字符串字节数组的长度int length = BitConverter.ToInt32(bytes, index);index += 4;s.name = Encoding.UTF8.GetString(bytes, index, length);index += length;//读 numbers.number = BitConverter.ToInt32(bytes, index);index += 4;//读 sexs.sex = BitConverter.ToBoolean(bytes, index);index += 1; }return s;}
}
C#类对象的序列化和反序列化

序列化





反序列化


加密




练习
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine;public class BinaryDataMgr
{private static BinaryDataMgr instance = new BinaryDataMgr();public static BinaryDataMgr Instance => instance;private static string SAVE_PATH = Application.persistentDataPath + "/Data/";private BinaryDataMgr(){}/// <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 + ".set", FileMode.OpenOrCreate, FileAccess.Write)){BinaryFormatter bf = new BinaryFormatter();bf.Serialize(fs, obj);fs.Close();}}/// <summary>/// 读取2进制数据转换成对象/// </summary>/// <typeparam name="T"></typeparam>/// <param name="fileNmae"></param>/// <returns></returns>public T Load<T>(string fileName) where T : class{//如果不存在这个文件 就直接返回泛型对象的默认值if (!File.Exists(SAVE_PATH + fileName + ".set"))return default(T);T obj;using(FileStream fs = File.Open(SAVE_PATH + fileName + ".set", FileMode.Open, FileAccess.Read)){BinaryFormatter bf = new BinaryFormatter();obj = bf.Deserialize(fs) as T;fs.Close();}return obj;}}



总结





实践小项目

知识点补充

Unity中添加菜单栏功能



Excel数据读取
导入Excel相关Dll包



Excel数据读取



需求分析
Excel配置表数据功能

制定配置表规则
分别空出一行来表示数据类型
空出一行标明 唯一ID(用于字典的Key)
空出一行 作为描述信息



读取Excel目录下所有Excel文件


生成数据结构类
using Excel;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.IO;
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";[MenuItem("GameTool/GenerateExcel")]private static void GenerateExcel(){//记录指定路径中的所有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;//Debug.Log(files[i].Name);//打开一个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){Debug.Log(table.TableName);//生成数据结构类GenerateExcelDataClass(table);//生成容器类//生成2进制数据}}}/// <summary>/// 生成Excel表对应的数据结构类/// </summary>/// <param name="table"></param>private static void GenerateExcelDataClass(DataTable table){//字段名行DataRow rowName = GetVariableNameRow(table);//字段类型行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>/// 获取变量名所在的行 方便以后修改/// </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];}
}

生成表容器类
using Excel;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.IO;
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/";[MenuItem("GameTool/GenerateExcel")]private static void GenerateExcel(){//记录指定路径中的所有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;//Debug.Log(files[i].Name);//打开一个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){Debug.Log(table.TableName);//生成数据结构类GenerateExcelDataClass(table);//生成容器类GenerateExcelContainer(table);//生成2进制数据}}}/// <summary>/// 生成Excel表对应的数据结构类/// </summary>/// <param name="table"></param>private static void GenerateExcelDataClass(DataTable table){//字段名行DataRow rowName = GetVariableNameRow(table);//字段类型行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>/// 获取变量名所在的行 方便以后修改/// </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>/// 生成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>/// 获取主键索引/// </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++){//得到 key的那一列if (row[i].ToString() == "key")return i;}//如果没有设置 就传回0return 0;}
}


生成Excel 2进制数据
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>/// 2进制数据存储位置路径/// </summary>public static string DATA_BINARY_PATH = Application.streamingAssetsPath + "/Binary/";/// <summary>/// 真正内容开始的行号/// </summary>public static int BEGIN_INDEX = 4;[MenuItem("GameTool/GenerateExcel")]private static void GenerateExcel(){//记录指定路径中的所有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;//Debug.Log(files[i].Name);//打开一个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){Debug.Log(table.TableName);//生成数据结构类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 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>/// 获取变量名所在的行 方便以后修改/// </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>/// 生成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>/// 获取主键索引/// </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++){//得到 key的那一列if (row[i].ToString() == "key")return i;}//如果没有设置 就传回0return 0;}/// <summary>/// 生成excel 2进制数据/// </summary>/// <param name="table"></param>private static void GenerateExcelBinary(DataTable table){// 判断路径是否存在, 不存在就创建if (!Directory.Exists(DATA_BINARY_PATH))Directory.CreateDirectory(DATA_BINARY_PATH);//创建一个2进制文件进行写入using(FileStream fs = new FileStream(DATA_BINARY_PATH + table.TableName + ".set", 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();}//属性 Project 窗口AssetDatabase.Refresh();}
}

表加载使用功能
在 BinaryDataMgr 的基础上进行修改
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;public class BinaryDataMgr
{private static BinaryDataMgr instance = new BinaryDataMgr();public static BinaryDataMgr Instance => instance;/// <summary>/// 用于存储所有Excel表数据的容器/// </summary>private Dictionary<string, object> tableDic = new Dictionary<string, object>();/// <summary>/// 数据存储的位置/// </summary>private static string SAVE_PATH = Application.persistentDataPath + "/Data/";/// <summary>/// 2进制数据存储位置路径/// </summary>public static string DATA_BINARY_PATH = Application.streamingAssetsPath + "/Binary/";private BinaryDataMgr(){}public void InitData(){//LoadTable<TowerInfoContainer, TowerInfo>();//LoadTable<PlayerInfoContainer, PlayerInfo>();//LoadTable<TestInfoContainer, TestInfo>();}/// <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 + ".set", 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 + ".set", FileMode.OpenOrCreate, FileAccess.Write)){BinaryFormatter bf = new BinaryFormatter();bf.Serialize(fs, obj);fs.Close();}}/// <summary>/// 读取2进制数据转换成对象/// </summary>/// <typeparam name="T"></typeparam>/// <param name="fileNmae"></param>/// <returns></returns>public T Load<T>(string fileName) where T : class{//如果不存在这个文件 就直接返回泛型对象的默认值if (!File.Exists(SAVE_PATH + fileName + ".set"))return default(T);T obj;using(FileStream fs = File.Open(SAVE_PATH + fileName + ".set", FileMode.Open, FileAccess.Read)){BinaryFormatter bf = new BinaryFormatter();obj = bf.Deserialize(fs) as T;fs.Close();}return obj;}}
注:这段代码遗留了个报错,暂时没能解决!!!

注:报错原因找到了,在配置Excel数据表格时一定不要手贱多打空格,多打的话二进制编译时会编译进去,然后读写出来时一些索引就会出问题!!!
(我是因为这个int后面加了个空格,导致string读取长度时读出一亿多的字符串长度,服啦!)

导出通用工具包



相关文章:
Unity数据持久化4——2进制
概述 基础知识 各类型数据转字节数据 文件操作相关 文件相关 文件流相关 文件夹相关 练习题 using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; using UnityEngine;public class Exercises1 : MonoBehaviour {/…...
经典sql题(八)SQL 查询详细指南总结一
SQL 查询详细指南 SQL(Structured Query Language)是一种用于管理和操作关系数据库的标准语言。本文将详细介绍 SQL 中的一些常见操作及其用法,包括 DISTINCT 去重、LIMIT 限制、排序、开窗函数、NULL 值替换、JOIN 与 UNION 等。 1. DISTI…...
用Python实现时间序列模型实战——Day 30: 学习总结与未来规划
在第30天,我们将对整个学习过程进行总结,复习关键知识点,并展望未来的学习与应用方向。我们将涵盖时间序列分析过程中涉及的主要模型、技术和工具,总结它们的优势和应用场景。此外,规划未来如何进一步深入学习…...
ChatGPT居然主动勾引用户,OpenAI又测试新功能? 一文教你学会订阅
有网友表示,他收到了ChatGPT主动给他发送的消息,询问“你高中的第一周过得怎么样?还适应吗?” 他很懵逼的回了一句“你刚才是给我发消息吗?”。也就是说,在没有任何先前文本提示下,ChatGPT主动…...
基于SpringBoot+Vue的考研百科网站系统
作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、SSM项目源码 精品专栏:Java精选实战项目源码、Python精…...
深度之眼(三十)——pytorch(一)--深入浅出pytorch(附安装流程)
文章目录 一、前言一、pytoch二、六个部分三、如何学习四、学习路径(重要)五、安装pytorch5.1 坑15.2 坑2 一、前言 我看了下目录 第一章和第二章都是本科学的数字图像处理。 也就是这一专栏:数字图像实验。 所以就不准备学习前两章了,直接…...
麒麟银河桌面版,成功安装cuda12.6,mysql
一、 要卸载并禁用 nouveau 驱动程序,可以按照以下步骤进行: 1. 确认 nouveau 驱动的当前状态: 首先,你可以使用以下命令查看 nouveau 驱动是否正在运行: lsmod | grep nouveau如果有输出,说明 nouveau …...
CentOS 7 YUM源不可用
CentOS 7 操作系统在2024年6月30日后将停止官方维护,并且官方提供的YUM源将不再可用。 修改:nano /etc/yum.repos.d/CentOS-Base.repo # CentOS-Base.repo [base] nameCentOS-$releasever - Base baseurlhttp://mirrors.aliyun.com/centos/$rel…...
Java反序列化利用链篇 | URLDNS链
文章目录 URLDNS链调用链分析Payload编写 系列篇其他文章,推荐顺序观看~ Java反序列化利用链篇 | JdbcRowSetImpl利用链分析Java反序列化利用链篇 | CC1链_全网最菜的分析思路Java反序列化利用链篇 | CC1链的第二种方式-LazyMap版调用链Java反序列化利用链篇 | URLD…...
Android 短信验证码自动填充
本文主要介绍国外google上线的app 短信自动填充方案。 本方案主要是使用google提出的,防止开发者使用SMS相关权限造成的用户信息泄露 目录 注意点: 1、本方式不适合华为手机,华为有自己的获取方式 2、本方式不需要添加任何短信权限 3、…...
数据库 MySQL 是否需要容器化?
容器的定义:容器是为了解决“在切换运行环境时,如何保证软件能够正常运行”这一问题。 目前,容器和 Docker 依旧是技术领域最热门的词语,无状态的服务容器化已经是大势所趋,同时也带来了一个热点问题被大家所争论不以…...
Kettle的安装及简单使用
Kettle的安装及简单使用一、kettle概述二、kettle安装部署和使用Windows下安装案例1:MySQL to MySQL案例2:使用作业执行上述转换,并且额外在表stu2中添加一条数据案例3:将hive表的数据输出到hdfs案例4:读取hdfs文件并将…...
Golang | Leetcode Golang题解之第420题强密码检验器
题目: 题解: func strongPasswordChecker(password string) int {hasLower, hasUpper, hasDigit : 0, 0, 0for _, ch : range password {if unicode.IsLower(ch) {hasLower 1} else if unicode.IsUpper(ch) {hasUpper 1} else if unicode.IsDigit(ch)…...
面试金典题3
URL化。编写一种方法,将字符串中的空格全部替换为%20。假定该字符串尾部有足够的空间存放新增字符,并且知道字符串的“真实”长度。 示例 1: 输入:"Mr John Smith ", 13 输出:"Mr%20John%20Smith&…...
FFmpeg开发笔记(五十六)使用Media3的Exoplayer播放网络视频
Android早期的MediaPlayer控件对于网络视频的兼容性很差,所以后来单独推出了Exoplayer库增强支持网络视频,在《Android Studio开发实战:从零基础到App上线(第3版)》一书第14章的“14.3.3 新型播放器ExoPlayer”就详细介绍了Exoplayer库的详细…...
Python使用总结之py-docx将word文件中的图片保存,并将内容返回
Python使用总结之py-docx将word文件中的图片保存,并将内容返回 使用py-docx读取word文档的内容,其中包含标题、文本和图片等信息。该方法将标题和内容返回,并将文件中的图片保存到指定的文件夹中。 实现步骤 加载文件内容读取文件的段落对文…...
Radware 报告 Web DDoS 攻击活动
新一代 HTTPS 洪水攻击的频率和强度急剧增加,攻击者引入的复杂程度也在迅速提高。2024 年上半年,Web 分布式拒绝服务 (DDoS) 攻击的频率和强度显著增加。其中很大一部分活动可以归因于受政治紧张局势驱使的黑客活动分子。 众所周知,当今的黑…...
OpenCV运动分析和目标跟踪(2)累积操作函数accumulateSquare()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 将源图像的平方加到累积器图像中。 该函数将输入图像 src 或其选定区域提升到2的幂次方,然后加到累积器 dst 中: dst ( …...
PCIe进阶之TL:Common Packet Header Fields TLPs with Data Payloads Rules
1 Transaction Layer Protocol - Packet Definition TLP有四种事务类型:Memory、I/O、Configuration 和 Messages,两种地址格式:32bit 和 64bit。 构成 TLP 时,所有标记为 Reserved 的字段(有时缩写为 R)都必须全为0。接收者Rx必须忽略此字段中的值,PCIe Switch 必须对…...
Linux之实战命令01:xargs应用实例(三十五)
简介: CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布:《Android系统多媒体进阶实战》🚀 优质专栏: Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏: 多媒体系统工程师系列【…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的----NTFS源代码分析--重要
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的 第一部分: 0: kd> g Breakpoint 9 hit Ntfs!ReadIndexBuffer: f7173886 55 push ebp 0: kd> kc # 00 Ntfs!ReadIndexBuffer 01 Ntfs!FindFirstIndexEntry 02 Ntfs!NtfsUpda…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...


