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工程师进阶系列【原创干货持续更新中……】🚀 优质专栏: 多媒体系统工程师系列【…...

CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...

sshd代码修改banner
sshd服务连接之后会收到字符串: SSH-2.0-OpenSSH_9.5 容易被hacker识别此服务为sshd服务。 是否可以通过修改此banner达到让人无法识别此服务的目的呢? 不能。因为这是写的SSH的协议中的。 也就是协议规定了banner必须这么写。 SSH- 开头,…...