当前位置: 首页 > news >正文

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读取长度时读出一亿多的字符串长度,服啦!)

导出通用工具包

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【CSS in Depth 2 精译_031】5.3 Grid 网格布局的两种替代语法
  • cpp中的namespace详解
  • 【C++】list详解及模拟实现
  • 软RAID查看状态mdstat的原理
  • 跨越数据孤岛:打造支持多种数据库的Java智能查询引擎及其商业前景
  • C# winforms DataGridView设置数据源自动显示表格
  • JAVA基础:Lock锁
  • imo云办公室 Imo_DownLoadUI.php 任意文件下载漏洞复现
  • Amesim-帮助文件翻译与总结-重要元件之firstorderlag
  • 小琳AI课堂:确保大语言模型安全的八大策略--从数据隐私到用户教育
  • Effective Java 学习笔记 方法签名设计
  • 使用python用递归实现汉诺塔算法
  • 三种springboot启动时加载方式
  • 蓝桥杯【物联网】零基础到国奖之路:十. OLED
  • 花朵识别系统Python+卷积神经网络算法+人工智能+深度学习+计算机课设项目+TensorFlow+模型训练
  • 【Leetcode】101. 对称二叉树
  • 4. 路由到控制器 - Laravel从零开始教程
  • Android Volley源码解析
  • ComponentOne 2017 V2版本正式发布
  • HTML-表单
  • mysql常用命令汇总
  • Nacos系列:Nacos的Java SDK使用
  • react 代码优化(一) ——事件处理
  • springboot_database项目介绍
  • springMvc学习笔记(2)
  • 初识MongoDB分片
  • 聊聊redis的数据结构的应用
  • 前端每日实战 2018 年 7 月份项目汇总(共 29 个项目)
  • 删除表内多余的重复数据
  • 适配mpvue平台的的微信小程序日历组件mpvue-calendar
  • scrapy中间件源码分析及常用中间件大全
  • ​软考-高级-系统架构设计师教程(清华第2版)【第1章-绪论-思维导图】​
  • ​油烟净化器电源安全,保障健康餐饮生活
  • (175)FPGA门控时钟技术
  • (MonoGame从入门到放弃-1) MonoGame环境搭建
  • (五十)第 7 章 图(有向图的十字链表存储)
  • (一)pytest自动化测试框架之生成测试报告(mac系统)
  • (一)十分简易快速 自己训练样本 opencv级联haar分类器 车牌识别
  • (译) 理解 Elixir 中的宏 Macro, 第四部分:深入化
  • *ST京蓝入股力合节能 着力绿色智慧城市服务
  • .NET CLR Hosting 简介
  • .NET CORE 3.1 集成JWT鉴权和授权2
  • .NET HttpWebRequest、WebClient、HttpClient
  • .NET 自定义中间件 判断是否存在 AllowAnonymousAttribute 特性 来判断是否需要身份验证
  • .NET开源快速、强大、免费的电子表格组件
  • .net企业级架构实战之7——Spring.net整合Asp.net mvc
  • .NET运行机制
  • .Net中的集合
  • .NET中使用Protobuffer 实现序列化和反序列化
  • .vimrc php,修改home目录下的.vimrc文件,vim配置php高亮显示
  • ;号自动换行
  • @Autowired标签与 @Resource标签 的区别
  • @ConditionalOnProperty注解使用说明
  • [ 数据结构 - C++] AVL树原理及实现
  • [000-01-030].Zookeeper学习大纲