.NET编程技术——实验07:Windows的注册表的基本使用方法,文件流保存为文本文件基础用法
2018-01-09 17:51
766 查看
阅读须知:纯粹是本人啊Jun作为初学者的笔记和个人对其中知识的复习,大神请绕道。
实验01:VS2015 对象浏览器的使用、简单调试和断点使用。
实验04:RS485串口调试、基本控件使用、CRC算法应用
实验05:RS485串口通讯,串口指令的收发应用,完成串口基础功能,github地址:实验05
实验06:窗体应用的最小化在Windows状态栏中显示托盘图标
实验07:Windows的注册表的基本使用方法,文件流保存为文本文件基础用法
实验08:利用GDI+技术生成简单验证码,类似excel的数据折线图、并保存为图片
实验09:Access数据库的创建、表创建、MD5加密,数据、图片保存在数据库的用法
实验10:将DataGridView表单数据保存为excel文件,表单的基本格式化
包含实验06~实验10的功能:github地址:实验10
来看一下实验07题目:
1、添加子菜单和相应的窗体,收发数据,译码,显示当前温度;
2、添加子菜单和相应的窗体,可设置通讯各参数,可以进行CRC校验值测试;
3、添加子菜单和相应的窗体,可进行用户密码的设置和
1605e
修改,可删除/添加用户,用户和密码信息保存在注册表中;
4、按照规则,如一天一个数据文件,或新建一个文件等,把测量到的温度值保存到文本文件中,要求最少有4列:序号、日期时间、用户名、温度值;
5、添加子菜单和相应的窗体,可以显示保存的数据文件的内容,但不能修改。
第 1 题的显示温度功能:在实验05中已经说过了,.NET编程技术——实验05,可以参考一下
第2
题的CRC功能:在实验04中也实现了, .NET编程技术——实验04,可以参考一下
3、添加子菜单和相应的窗体,可进行用户密码的设置和修改,可删除/添加用户,用户和密码信息保存在注册表中;
可以 Win+R ,输入regedit,便可以出现注册表了
先看一下效果图:
注册窗体,下为注册一个普通用户:现在还想表达的是,密码在注册表里进行RAS加密,原密码是123,看看加密后的密码是什么。
经过RAS加密后,密码就变成了如下的字符串
在讲注册表之前,先来普及一下知识,如下图所示,
结合上图和下面代码的注释,我觉得理解注册表已经没有什么问题了。
好了,那现在来开始讲一下注册表 和RAS 加密
注册表,我专门给注册表的操作整合出了一个 Redegit类 ,
RSA 加密,我专门给
RSA加密 整合出一个 RSA类
结合上面的 注册窗体 来说吧,
注册窗体代码
注册表: Redegit类
RSA加密类: RSA类
(用法)
ok,添加用户写好了,那就下面写一下 删除用户吧,删除用户的权限只有管理员才有的,
点击‘-’进行删除用户操作,combobox出现了注册里的“user”中两个一般用户,我想的是没有删除管理员的功能,目标为了管理员只有在注册表才能删除,为了安全。
这里加了一个小操作,现在的user已经不在combobox上了,由于暂时无法实现控件的自动更新,之前尝试了Control.Refresh() 或者Timer控件都无法实现控件更新,所以做了如下的小操作,满足自己强迫症.
,哈哈哈哈
下面附上删除用户的代码:
再到修改密码功能:
附上代码:
下面搞完第3 题了,妈呀,注册表的增删改查,,全做了,以后的实验中还有ACCESS的数据库的增删改查,想想都兴奋
4、按照规则,如一天一个数据文件,或新建一个文件等,把测量到的温度值保存到文本文件中,要求最少有4列:序号、日期时间、用户名、温度值;
下面终于到最关键的时刻了,就是保存txt文件
这里就涉及到文件流的操作了
其实不算难,只要注意文件流的关闭和打开就Ok了,假如你的 StreamReader 读取完没有 close掉的话,就不能用 StreamWriter 写文件了。
在 .txt文件中写入数据时候,我放在了“串口数据接收事件”,serialPort_DataReceived,实验05 有提到,
既然讲到了文件操作,那我索性讲一下文件夹的操作吧。
其实文件夹的操作并不难,但是我觉得有趣的是创建文件的 URL ,很多时候,我们习惯按顺序填文件的 URL,如下图
但是有一次用我的程序放在别人的电脑上用的时候,很多时候会出问题,原因是别人的电脑路径有别。突然想起了PHP老师曾经教过我们文件夹都是返回上一层这样才能正常使用的,所以我找到C#的文件退级的方法,如下。
我们运行的程序,其实是从Debug共返回了三层,
第 5 题了,啊,这次任务真多,胜利就在前方啊,同学们
5、添加子菜单和相应的窗体,可以显示保存的数据文件的内容,但不能修改。
题目意思其实就是查看刚刚保存的
.txt 文件,首先看到是只能看,不能修改,
那好办,我直接在
RichTextBox 控件中添加数据就好了,顺便改RichTextBox 的属性ReadOnly = true就好了
附上代码:
其中一个文件对话框类:OpenFileDialog,确实很常用,建议大家可以找一下这方面的知识,以后的实验可能会讲到
效果如下:
实验07完成
,如果有疑问或者在哪些地方有错误的,欢迎大家指出,共同学习,共同进步。
实验01:VS2015 对象浏览器的使用、简单调试和断点使用。
实验04:RS485串口调试、基本控件使用、CRC算法应用
实验05:RS485串口通讯,串口指令的收发应用,完成串口基础功能,github地址:实验05
实验06:窗体应用的最小化在Windows状态栏中显示托盘图标
实验07:Windows的注册表的基本使用方法,文件流保存为文本文件基础用法
实验08:利用GDI+技术生成简单验证码,类似excel的数据折线图、并保存为图片
实验09:Access数据库的创建、表创建、MD5加密,数据、图片保存在数据库的用法
实验10:将DataGridView表单数据保存为excel文件,表单的基本格式化
包含实验06~实验10的功能:github地址:实验10
实验01:VS2015 对象浏览器的使用、简单调试和断点使用。
实验04:RS485串口调试、基本控件使用、CRC算法应用
实验05:RS485串口通讯,串口指令的收发应用,完成串口基础功能,github地址:实验05
实验06:窗体应用的最小化在Windows状态栏中显示托盘图标
实验07:Windows的注册表的基本使用方法,文件流保存为文本文件基础用法
实验08:利用GDI+技术生成简单验证码,类似excel的数据折线图、并保存为图片
实验09:Access数据库的创建、表创建、MD5加密,数据、图片保存在数据库的用法
实验10:将DataGridView表单数据保存为excel文件,表单的基本格式化
包含实验06~实验10的功能:github地址:实验10
来看一下实验07题目:
1、添加子菜单和相应的窗体,收发数据,译码,显示当前温度;
2、添加子菜单和相应的窗体,可设置通讯各参数,可以进行CRC校验值测试;
3、添加子菜单和相应的窗体,可进行用户密码的设置和
1605e
修改,可删除/添加用户,用户和密码信息保存在注册表中;
4、按照规则,如一天一个数据文件,或新建一个文件等,把测量到的温度值保存到文本文件中,要求最少有4列:序号、日期时间、用户名、温度值;
5、添加子菜单和相应的窗体,可以显示保存的数据文件的内容,但不能修改。
第 1 题的显示温度功能:在实验05中已经说过了,.NET编程技术——实验05,可以参考一下
第2
题的CRC功能:在实验04中也实现了, .NET编程技术——实验04,可以参考一下
3、添加子菜单和相应的窗体,可进行用户密码的设置和修改,可删除/添加用户,用户和密码信息保存在注册表中;
可以 Win+R ,输入regedit,便可以出现注册表了
先看一下效果图:
注册窗体,下为注册一个普通用户:现在还想表达的是,密码在注册表里进行RAS加密,原密码是123,看看加密后的密码是什么。
经过RAS加密后,密码就变成了如下的字符串
在讲注册表之前,先来普及一下知识,如下图所示,
结合上图和下面代码的注释,我觉得理解注册表已经没有什么问题了。
好了,那现在来开始讲一下注册表 和RAS 加密
注册表,我专门给注册表的操作整合出了一个 Redegit类 ,
RSA 加密,我专门给
RSA加密 整合出一个 RSA类
结合上面的 注册窗体 来说吧,
注册窗体代码
public partial class RegisterForm : Form { private RSA ras; private Regedit registry; //注册表变量 private Regedit adminRegistry; private Regedit userRegistry; public RegisterForm() { InitializeComponent(); } /// <summary> /// 实现“注册表”的注册 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void RegisterForm_Load(object sender, EventArgs e) { // primaryKey = Registry.CurrentUser; //注册在当前用户里,如果使用管理员运行该软件才能注册在LocalMachine里。 //softWare= primaryKey.CreateSubKey(@"SOFTWARE\JUN-SerialPort"); userCombobox.Items.Add("管理员"); userCombobox.Items.Add("一般用户"); userCombobox.Text = userCombobox.Items[0].ToString(); registry = new Regedit(Registry.CurrentUser, @"SOFTWARE\JUN-SerialPort"); //定义一个注册表 adminRegistry = new Regedit(Registry.CurrentUser, @"SOFTWARE\JUN-SerialPort\admin"); //定义管理员注册表 userRegistry = new Regedit(Registry.CurrentUser, @"SOFTWARE\JUN-SerialPort\user"); //定义用户注册表 ras = new RSA(); //定义一个RAS对象,用于加密和解密 } /// <summary> /// "确定"按钮事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void okButton_Click(object sender, EventArgs e) { string userName = userNameTextBox.Text.Trim(); //去除字符串前后面的空格 string password = passwordTextBox.Text.Trim(); //if (String.IsNullOrEmpty(userNameTextBox.Text)) if (userName != String.Empty ) { if (password != String.Empty) { if (String.Equals(password, passwordTextBox2.Text.Trim())) //两次密码相同 { if (userCombobox.Text == "管理员") { //数据库和注册表同时操作 if (adminRegistry.isRegistryValueNameExist(userName)) { MessageBox.Show("该管理员已存在!"); } else { //下面要对密码进行加密再储存在注册表里面 adminRegistry.SetValue(userName, ras.Encryption(password), RegistryValueKind.String); MessageBox.Show("恭喜管理员 “" + userName + "” 注册成功"); this.DialogResult = DialogResult.Yes; //this.Close(); } } else { if (userRegistry.isRegistryValueNameExist(userName)) { MessageBox.Show("该用户已存在!"); } else { //下面要对密码进行加密再储存在注册表里面 userRegistry.SetValue(userName, ras.Encryption(password), RegistryValueKind.String); MessageBox.Show("恭喜用户 “" + userName + "” 注册成功"); this.DialogResult = DialogResult.Yes; //this.Close(); } } } else MessageBox.Show("两次输入密码不一致"); } else MessageBox.Show("输入密码不能为空"); } else MessageBox.Show("用户名不能为空"); } private void cancelButton_Click(object sender, EventArgs e) { this.Close(); } }
注册表: Redegit类
using Microsoft.Win32; //需要引用Win32,因为需要用到注册表类型: RegistryKey 类型
public class Regedit { private RegistryKey softWare; //注册表类型变量 private string[] sValueNameColl; //键值表项 private string[] sKeyNameColl; //注册表项 private RSA ras = new RSA(); // 这是我整合的 RSA 常用的方法的一个类 /// <summary> /// 构造函数 /// </summary> /// <param name="registry">判断哪里添加注册表</param> /// <param name="subKey">注册表的软件名称</param> public Regedit(RegistryKey registry, string subKey) { this.softWare = registry.CreateSubKey(subKey); //创建一个新子项或打开一个现有子项以进行写访问。 // this.softWare = registry.OpenSubKey(subKey,true); //需要加上true才能对键值进行写操作,否则默认是读操作 sKeyNameColl = softWare.GetValueNames(); sValueNameColl = softWare.GetValueNames(); //获取JUN-SerialPort所有子项 } /// <summary> /// 判断键值是否存在 /// </summary> /// <param name="sValueName">注册表名 </param> /// <param name="value">返回键值的值</param> /// <returns></returns> public bool isRegistryValueNameExist(string sValueName, ref string value) { foreach (string sName in sValueNameColl) { if (sName == sValueName) //如果键匹配了 { value = ras.Decrypt(Convert.ToString(softWare.GetValue(sName))); //那就将该键的值,即密码,进行RSA解密 return true; } } return false; } /// <summary> /// 判断键值是否存在 /// </summary> /// <param name="sValueName">注册表名 </param> /// <returns></returns> public bool isRegistryValueNameExist(string sValueName) { foreach (string sName in sValueNameColl) { if (sName == sValueName) { return true; } } return false; } /// <summary> /// 在注册表里添加键值 /// </summary> /// <param name="name"></param> /// <param name="value"></param> /// <param name="valueKind"></param> public void SetValue(string name,string value, Microsoft.Win32.RegistryValueKind valueKind) { try { softWare.SetValue(name, value, valueKind); } catch(Exception ex) { MessageBox.Show("出现异常:"+ex); } } /// <summary> /// 返回所有键值 /// </summary> /// <returns></returns> public string[] GetKeyNames() { return sValueNameColl; } /// <summary> /// 删除注册表键值 /// </summary> /// <param name="keyName">键值</param> /// <returns></returns> public bool DeleteKey(string keyName) { if (sValueNameColl.Length > 0) { softWare.DeleteValue(keyName); //只需要删除其中的键,那么键和值都会被删除 return true; } else return false; } }
RSA加密类: RSA类
(用法)
using System.Security; //RAS加密需要引用的包 using System.Security.Cryptography;
public class RSA { /// <summary> /// 使用”RSA“加密 /// </summary> /// <param name="express"></param> /// <returns></returns> public string Encryption(string express) { CspParameters param = new CspParameters(); //CspParameters: 包含传递给执行加密计算的加密服务提供程序(CSP) 的参数 param.KeyContainerName = "JunKey"; //密钥容器的名称,保持加密解密一致才能解密成功 using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(param)) { byte[] plainData = Encoding.Default.GetBytes(express); //将要加密的字符串转换为字节数组 byte[] encryptData = rsa.Encrypt(plainData, false);//将加密后的字节数据转换为新的加密字节数组 return Convert.ToBase64String(encryptData); //将加密后的字节数组转换为字符串 } } /// <summary> /// 使用”RSA“解密 /// </summary> /// <param name="ciphertext"></param> /// <returns></returns> public string Decrypt(string ciphertext) { CspParameters param = new CspParameters(); param.KeyContainerName = "JunKey"; //密钥容器的名称,保持加密解密一致才能解密成功 using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(param)) { byte[] encrytData = Convert.FromBase64String(ciphertext); byte[] decryptData = rsa.Decrypt(encrytData, false); return Encoding.Default.GetString(decryptData); } } }
ok,添加用户写好了,那就下面写一下 删除用户吧,删除用户的权限只有管理员才有的,
点击‘-’进行删除用户操作,combobox出现了注册里的“user”中两个一般用户,我想的是没有删除管理员的功能,目标为了管理员只有在注册表才能删除,为了安全。
这里加了一个小操作,现在的user已经不在combobox上了,由于暂时无法实现控件的自动更新,之前尝试了Control.Refresh() 或者Timer控件都无法实现控件更新,所以做了如下的小操作,满足自己强迫症.
,哈哈哈哈
下面附上删除用户的代码:
/// <summary> /// 加载“注册表”的用户 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void DeleteUser_Load(object sender, EventArgs e) { regedit = new Regedit(Registry.CurrentUser, @"SOFTWARE\JUN-SerialPort\user"); keyNames = regedit.GetKeyNames(); foreach (string name in keyNames) userComboBox.Items.Add(name); if (keyNames.Length > 0) { userComboBox.Text = userComboBox.Items[0].ToString(); } }
/// <summary> /// 点击“确定”删除 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void sureButton_Click(object sender, EventArgs e) { if (keyNames.Length == 0) MessageBox.Show("对不起,用户为空,没有用户可以删除!"); else //键值不为空 { if (userComboBox.Items.Count == 1) userComboBox.Text = userComboBox.Items[0].ToString(); else userComboBox.Text = userComboBox.Items[userComboBox.SelectedIndex].ToString(); if (MessageBox.Show("你将要删除用户 “" + userComboBox.Text + "” 吗?", "删除用户", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK) { if (regedit.DeleteKey(userComboBox.Text) && access.deleteUser("一般用户", userComboBox.Text)) //在数据库和注册表内一起删除 { MessageBox.Show("删除成功!"); userComboBox.Items.Clear(); //先将Combobox清空 DeleteUser_Load(sender, e); //再重新加载 } else MessageBox.Show("删除失败!"); } } }
再到修改密码功能:
附上代码:
/// <summary> /// "确认修改"按钮事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void changeButton_Click(object sender, EventArgs e) { string oldPwd = null; if (LoginForm.userType == "管理员") { adminRegistry.isRegistryValueNameExist(LoginForm.userName, ref oldPwd); } else //用户类型是 “一般用户” { userRegistry.isRegistryValueNameExist(LoginForm.userName, ref oldPwd); } if (oldPWDTextbox.Text == oldPwd) //如果旧密码输入正确才能修改密码 { if (newPWDTextBox.Text.Trim() != String.Empty) { if (newPWDTextBox.Text.Trim() == newPWDTextBox2.Text.Trim()) { if (LoginForm.userType == "管理员") //“管理员修改密码” { //下面要对密码进行加密再储存在注册表里面 adminRegistry.SetValue(LoginForm.userName, ras.Encryption(newPWDTextBox.Text.Trim()), RegistryValueKind.String); } else //“一般用户修改密码” { userRegistry.SetValue(LoginForm.userName, ras.Encryption(newPWDTextBox.Text.Trim()), RegistryValueKind.String); } MessageBox.Show("修改成功!"); } else MessageBox.Show("两次密码输入不一致"); } else MessageBox.Show("输入密码不能为空"); } else { MessageBox.Show("原密码输入错误"); } }
下面搞完第3 题了,妈呀,注册表的增删改查,,全做了,以后的实验中还有ACCESS的数据库的增删改查,想想都兴奋
4、按照规则,如一天一个数据文件,或新建一个文件等,把测量到的温度值保存到文本文件中,要求最少有4列:序号、日期时间、用户名、温度值;
下面终于到最关键的时刻了,就是保存txt文件
这里就涉及到文件流的操作了
private FileStream file;//格式:每天一个文件 private StreamWriter fileWriter; //用于写文件 private StreamReader fileReader; //用于读取文件的行数 private static int line = 0; //静态变量,表示记录数
其实不算难,只要注意文件流的关闭和打开就Ok了,假如你的 StreamReader 读取完没有 close掉的话,就不能用 StreamWriter 写文件了。
if (File.Exists(temperatureFile + '\\' + fileName)) //判断记录温度的txt是否存在 { System.Diagnostics.Debug.Write("文件已经存在"); fileReader = new StreamReader(temperatureFile + '\\' + fileName); while (fileReader.ReadLine() != null) line++; System.Diagnostics.Debug.WriteLine("行数:" + line); fileReader.Close(); } else { file = File.Create(temperatureFile + '\\' + fileName); //如果该文件不存在,就需要创建 file.Close(); }
在 .txt文件中写入数据时候,我放在了“串口数据接收事件”,serialPort_DataReceived,实验05 有提到,
private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
fileWriter.WriteLine("序号:" + ++line + " 日期:"+ DateTime.Now.ToString()+" 用户名:"+ LoginForm.userName+" 温度:"+ tempTextBox.Text + "℃");当你写完数据的时候,也需要关闭 StreamWriter ,否则下一次运行程序的时候,也是会出现错误,那我选择在“关闭串口”的时候,加上 fileWriter.Close();
既然讲到了文件操作,那我索性讲一下文件夹的操作吧。
if (!Directory.Exists(imageFile)) //判断文件夹是否存在 { Directory.CreateDirectory(imageFile); //文件夹不存在,创建一个“温度折线图”文件夹 } if (!Directory.Exists(temperatureFile)) { Directory.CreateDirectory(temperatureFile); //文件夹不存在,创建一个“温度记录文件”文件夹 }
其实文件夹的操作并不难,但是我觉得有趣的是创建文件的 URL ,很多时候,我们习惯按顺序填文件的 URL,如下图
但是有一次用我的程序放在别人的电脑上用的时候,很多时候会出问题,原因是别人的电脑路径有别。突然想起了PHP老师曾经教过我们文件夹都是返回上一层这样才能正常使用的,所以我找到C#的文件退级的方法,如下。
我们运行的程序,其实是从Debug共返回了三层,
第 5 题了,啊,这次任务真多,胜利就在前方啊,同学们
5、添加子菜单和相应的窗体,可以显示保存的数据文件的内容,但不能修改。
题目意思其实就是查看刚刚保存的
.txt 文件,首先看到是只能看,不能修改,
那好办,我直接在
RichTextBox 控件中添加数据就好了,顺便改RichTextBox 的属性ReadOnly = true就好了
附上代码:
/// <summary> /// 打开文件选择导入 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void fileButton_Click(object sender, EventArgs e) { OpenFileDialog file = new OpenFileDialog(); file.Filter = "文本文件(*.txt) | *.txt"; //文本文件(*.txt) | *.txt | 所有文件(*.*) | *.* //file.ShowDialog(); //string name = file.FileName; //返回路径名和文件名 //System.Diagnostics.Debug.Write(name); DialogResult result = file.ShowDialog(); if (result == DialogResult.OK) ReadTextFile(@file.FileName); } /// <summary> /// 读取txt文件的数据 /// </summary> /// <param name="fileName"></param> private void ReadTextFile(string fileName) { readTextBox.Text = null; string[] lines = File.ReadAllLines(fileName,System.Text.Encoding.Default); foreach(string line in lines) { readTextBox.AppendText(line+Environment.NewLine); } }
其中一个文件对话框类:OpenFileDialog,确实很常用,建议大家可以找一下这方面的知识,以后的实验可能会讲到
OpenFileDialog file = new OpenFileDialog(); file.Filter = "文本文件(*.txt) | *.txt"; //文本文件(*.txt) | *.txt | 所有文件(*.*) | *.* //file.ShowDialog(); //string name = file.FileName; //返回路径名和文件名 //System.Diagnostics.Debug.Write(name); DialogResult result = file.ShowDialog(); if (result == DialogResult.OK) ReadTextFile(@file.FileName);
效果如下:
实验07完成
,如果有疑问或者在哪些地方有错误的,欢迎大家指出,共同学习,共同进步。
实验01:VS2015 对象浏览器的使用、简单调试和断点使用。
实验04:RS485串口调试、基本控件使用、CRC算法应用
实验05:RS485串口通讯,串口指令的收发应用,完成串口基础功能,github地址:实验05
实验06:窗体应用的最小化在Windows状态栏中显示托盘图标
实验07:Windows的注册表的基本使用方法,文件流保存为文本文件基础用法
实验08:利用GDI+技术生成简单验证码,类似excel的数据折线图、并保存为图片
实验09:Access数据库的创建、表创建、MD5加密,数据、图片保存在数据库的用法
实验10:将DataGridView表单数据保存为excel文件,表单的基本格式化
包含实验06~实验10的功能:github地址:实验10
相关文章推荐
- iOS开发OC基础:OC字典NSDictionary以及NSMutableDictionary基本方法的使用
- VC++开发中最简单的Multi-Byte(ANSI)和Unicode互转方法,灵活使用Windows基本API:wsprintfA, wsprintfW
- TFS2012团队管理基本配置及基础使用方法
- iOS开发OC基础:OC集合NSSet、NSMutableSet以及NSCountedSet的基本方法的使用
- QTableView基本用法讲解,Qt表格控件的使用方法
- Log4j基本使用方法(保存日志到控制台、文件、数据库中)
- Objective-C之foundation框架中的NSString的使用方法、指针基本用法、读取本地和远程文件
- C#基础精华07(委托事件,委托的使用,匿名方法)
- RecyclerView 使用方法总结(一):RecyclerView的基本用法,及实现ListView
- 【基础】SQLite的基本使用方法
- windows下boost库的基本使用方法
- 使用Java操作Windows注册表-Java基础-Java-编程开发
- UI 基础----UIScrollView 的基本属性使用以及代理的使用方法
- Java使用utf8格式保存文本文件的方法
- js中Map之基本用法分开单独写方法,当做类库使用
- Windows下Git的安装和基本使用方法
- QTableView基本用法讲解,Qt表格控件的使用方法
- C#基础精华07(委托事件,委托的使用,匿名方法)
- WINDOWS-基础:SafeArray的使用方法
- TFS2012团队管理基本配置及基础使用方法