数据持久化

文章目录

  • 数据持久化
    • 数据持久化概述
    • 1.数据持久化——JSON
      • 1.Json简介
      • 2.JsonUtility相关知识点
      • 3.LitJson相关知识
      • 4.JsonMgr管理器的书写
    • 2.数据持久化——二进制
      • 1.二进制简介
      • 2.文件操作
      • 3.流
      • 4.文件夹
      • 5.二进制序列化工具
        • **写一个工具读取Excel中的信息**:
        • **生成数据结构类的逻辑方法**:
        • **生成容器(字典)类**
        • **生成Excel二进制数据**:
        • **使用二进制数据读取使用**
    • 3.数据持久化——PlayerPrefs
      • 3.1 概述
      • 3.2 基础语法
      • 3.3 PlayerPrefs存储位置

数据持久化概述

定义:内存中的数据模型与存储模型的相互转化。
类比:将游戏数据存储到硬盘,从硬盘中读取游戏数据。

1.数据持久化——JSON

1.Json简介

定义: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


2.JsonUtility相关知识点

  • 1.定义:Unity自带的用于解析Json的公共类。
  • 2.作用:对象序列化为Json,Json反序列化为对象。
  • 3.用法:
    序列化
//存储字符串到指定路径文件中
//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);
  • 4.注意:
    – 1.自定义类序列化时需要加上特性 [System.Serializable]
    – 2.想要序列化私有的或者保护的变量可以加上特性 [SerializeField]
    – 3.JU不支持字典存储。
    – 4.JU存储null对象不会是null,而是变量类型默认值。
    – 5.JU无法直接读取(反序列化)数据集合(需要包装一层类)
    – 6.文本编辑器的编码格式必须是UTF-8,否则会报错。

3.LitJson相关知识

定义:第三方库,由C#编写,体积小速度快易于使用。
使用步骤

  • 1.进入其Github官方文档。
  • 2.获取代码引入项目即可。(最终拷贝的是LitJson文件夹核心代码模块,无需其他的文件)
  • 3.用法
    序列化
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);
  • 4.注意
    – 1.相对JsonUtility来说不需要加特性。
    – 2.不能序列号私有变量。
    – 3.支持字典类型,字典的键建议都是字符串。
    – 4.需要引用LitJson 命名空间。
    – 5.可以准确地保存null类型。
    – 6.反序列化时要保证指定对象存在无参构造函数。
    – 7.文本编码必须是UTF-8。

JsonUtility与LitJson对比
相同点:

  • 1.都是用于Json的序列化反序列化
  • 2.Json文档编辑器必须都是UTF-8
  • 3.都是通过静态类(JsonUtility和JsonMapper)进行方法调用

不同点:

  • 1.JU是Unity自带,LitJson是第三方,需要引入。
  • 2.JU使用自定义类需要加[System.Serializable]特性,LitJson不需要。
  • 3.JU支持私有变量(加特性[SerializField]),LitJson不需要。
  • 4.JU不支持字典,LitJson支持(key只能是字符串)。
  • 5.JU不能直接将数据反序列化为数据集合(字典),LitJson可以。
  • 6.JU堆自定义类不要求无参构造,LitJson要求必须存在无参构造。
  • 7.JU存储空对象时会存储默认值而不是null,LitJson会存null。

4.JsonMgr管理器的书写

/// <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;}
}

2.数据持久化——二进制

1.二进制简介

写在前面: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);

2.文件操作

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);

3.流

//打开或创建文件
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));}

4.文件夹

//判断文件夹是否存在
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();

5.二进制序列化工具

补充知识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()
{//文件流打开Excelusing(FileStream fs = File.Open(Application.dataPath + "/ArtRes/Excel/PlayerInfo.xlsx",FileMode.Open,FileAccess.Read)){//通过我们文件流获取ExcelIExcelDataReader 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表格生成以下信息:

  • 1.数据结构类
  • 2.装数据的容器
  • 3.二进制存储文件

写一个工具读取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);
}

生成Excel二进制数据

(放在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();
}

使用二进制数据读取使用

3.数据持久化——PlayerPrefs

3.1 概述

概念:PlayerPrefs是可以用于读取玩家数据的公共类。

3.2 基础语法

存储相关

//存储三种数据类型
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();

3.3 PlayerPrefs存储位置

Windows

存储路径:HKCU\Software\[公司名称]\[产品名称] 下的注册表中
打开方式:

  • 1.运行 regedit
  • 2.进入HKEY_CURRENT_USER->SOFTWARE
  • 3.进入Unity->UnityEditor->公司名称->产品名称

Android
存储路径:/data/data/包名/shared_prefs/pkg-name.xml

IOS
存储路径:/Libraray/Preferences/[应用ID].plist

数据持久化(Json,二进制,PlayerPrefs)相关推荐

  1. Unity之数据持久化——Json

    1.Json是什么 JavaScript对象简谱(JavaScript Object Notation) json是国际通用的一种轻量级的数据交换格式,主要在网络通讯中用于传输数据,或本地数据存储和读 ...

  2. Unity数据持久化——Json

    1.Json是什么? 全称: JavaScript对象简谱((JavaScript Object Notation) Json是国际通用的一种轻量级的数据交换格式 主要在网络通讯中用于传输数据,或本地 ...

  3. Unity数据持久化-Json

    文章目录 JSON概念: JSON结构: JSON优势: 与JavaScript的关系: Unity方法: 使用JsonUtility Json存储 Json加载: 注意事项: 完整代码参考: 使用L ...

  4. Unity3D 本地数据持久化记录存储

    本地数据持久化 一. PlayerPrefs 使用案例 二.xml 三.json 一. PlayerPrefs PlayerPrefs是unity自带的一个数据存储类 描述 PlayerPrefs 是 ...

  5. 数据持久化Xml与Json

    Unity中常用的序列化方式有三种,二进制序列化,xml,json 二进制序列化因为不能维护字段,通常用于图片,音频,视频等文件的传输 Xml相比Json有阅读直白的优势,通常用于配置表 Json效率 ...

  6. Unity3D游戏开发之数据持久化PlayerPrefs的使用

    unity3d提供了一个用于本地持久化保存与读取的类--PlayerPrefs.工作原理非常简单,以键值对的形式将数据保存在文件中,然后程序可以根据这个名称取出上次保存的数值.     PlayerP ...

  7. python变量持久化_Python 数据持久化:JSON

    Python 数据持久化:JSON 编程派微信号:codingpy 淡蓝色字体可以直接点击查看 上周更新的<Think Python 2e>第14章讲述了几种数据持久化的方式,包括dbm. ...

  8. 爬虫之scrapy框架的数据持久化存储/保存为scv,json文件

    文章目录 前情回顾 selenium+phantomjs/chrome/firefox execjs模块使用 今日笔记 scrapy框架 小试牛刀 猫眼电影案例 知识点汇总 数据持久化存储(MySQL ...

  9. 【Unity3D 教程系列第 15 篇】本地数据持久化之 Playerprefs 类

    这是[Unity3D 教程系列第 15 篇],如果觉得有用的话,欢迎关注专栏. 文章目录 一:什么是 PlayerPrefs 类 二:PlayerPrefs 类中的静态方法 1:写入数据 2:读取数据 ...

  10. 【Unity数据持久化_Json】(二)Excel转Json

    一.在Excel表中配置游戏数据 创建一个Excel文件,填写游戏数据 二.将Excel表中配置的数据转为Json配置 1.网页搜索Excel转Json 如:https://www.bejson.co ...

最新文章

  1. 拿下丰厚的年终奖,却未能拯救总薪酬,2021 年度 IT 薪酬调查报告出炉!
  2. 春运渡劫?Python帮你12306抢回家的火车票
  3. HDU 3584 Cube (三维树状数组)
  4. 【译】 WebSocket 协议第十二章——使用其他规范中的WebSocket协议
  5. 电信笔试c语言编程,华工电信院电子与通信工程 923复试面试,笔试考什么?复试真题...
  6. android 列表倒计时,Android利用RecyclerView实现列表倒计时效果
  7. php获取下载地址,php获取当前页面完整URL地址函数
  8. java 运行环境注册表_Java运行环境与Windows注册表
  9. 亚马逊ec2 实例删除_亚马逊免费使用套餐:在EC2 Linux实例上安装Tomcat 7
  10. SpringBoot-短信验证码-快速入门Demo(含redis)(手把手教你开通阿里云短信服务到写出个最终代码来)
  11. BZOJ 2120: 数颜色
  12. php7 libiconv,PHP7编译错误:php编译undefined reference to `libiconv 错误
  13. rtl驱动 ubuntu 禁用_Ubuntu如何安装rtl8822be驱动
  14. LaTeX 008:比较方便的键入下划线的方式
  15. 国外的英文JAVA论坛
  16. 网络安全宣传月安全团队需要知道的关于PKI的九件事
  17. C#获取动态网页中的数据
  18. LDO和DCDC电路的区别以及PCB设计选择
  19. ACRush 楼天成回忆录
  20. ProxmoxVE7.0+Ceph15.2集群搭建

热门文章

  1. 创建LabwindowsCVI工程
  2. Android解决手机图片压缩后旋转问题
  3. 微信小程序JavaScript语法介绍
  4. USBKey使用openssl链接
  5. 怎么把cad的图导入ps_如何将CAD图纸导入到Photoshop中编辑
  6. 传奇怎么修改服务器,如何修改传奇服务端路径
  7. linux系统可以安装企业微信,Linux 上安装微信客户端
  8. miix4linux双系统,联想Miix4 Pro一键重装系统win10教程
  9. 计算机一级改扩展名,怎么改文件扩展名,教您电脑win7改文件扩展名的方法
  10. Amazon EC2最新最全使用教程!!!