重点知识:
1、String常用方法:Contains、Split、StartsWith、EndsWith、IndexOf、SubString、Replace、Trim;判断一个字符串是null或者空的简单方法String.IsNullOrEmpty;
2、String s1=null;String s2="";String s3=" ";的区别是什么?
3、StringBuilder和String的区别是什么?
4、int可以为null吗?如果想表示可以为null的整数,应该怎样表示?
5、try……catch;try……finally;try……catch……finally;catch中的代码什么时候执行;finally中的代码什么时候执行;
6、如何判断一个文件是否存在;最简单的读取一个文本文件所有内容的方法是什么,有什么缺点?
7、如何遍历一个文件夹下所有的jpg图片?
8、FileStream和StreamReader/StreamWriter的区别是什么?
9、如何使用StreamReader读取一个文本文件?如果出现乱码是什么问题?
10、使用FileStream和StreamReader/StreamWriter应该如何正确的释放资源?
11、如何使用FileStream拷贝一个文件?
12、泛型List有哪些常见操作?泛型Dictionary有哪些常见操作?
13、什么样的对象可以使用foreach进行遍历?
------------------------------------------------
第 1 节 String常用方法1
成员方法:
bool Contains(String str):判断字符串对象是否包含给定的字符串。
bool StartsWith(String str):判断字符串对象是否以给定的字符串开始。
bool EndsWith(String str):判断字符串对象是否以给定的字符串结束。
/*string s1 = "Hello"; Console.WriteLine(s1.Contains("el")); Console.WriteLine(s1.Contains("abc")); */ /* Console.WriteLine(s1.StartsWith("He")); Console.WriteLine(s1.StartsWith("he")); */ /* string s = "http://www.rupeng.com"; if (s.StartsWith("https://") && (s.EndsWith(".com") || s.EndsWith(".cn"))) { Console.WriteLine("合法网址"); } else { Console.WriteLine("非法网址"); }*/ /* string email = "[email protected]"; string username = "毛**万岁"; if (email.EndsWith("@qq.com")) { Console.WriteLine("本站不支持QQ邮箱"); Console.ReadKey(); return; } if (username.Contains("毛 泽 东") || username.Contains("总书记")) { Console.WriteLine("用户名请勿使用敏感词汇"); Console.ReadKey(); return; }*/
案例:判断是否是网址:以http:// 开头,以 .com 或 .cn结尾。
*:好的编程习惯非常重要!
------------------------------------------------
第 2 节 String常用方法2
int Length:获取字符串的长度属性
char ch = s[3];
int IndexOf(int ch):返回指定字符在此字符串中第一次出现的索引
int IndexOf(String str):返回指定字符串在此字符串中第一次出现的索引
LastIndexOf:最后一次出现的位置。
String Substring(int start):截取字符串。返回从指定位置开始截取后的字符串。
String substring(int start,int length)截取字符串。返回从指定位置开始截取指定长度length的字符串。
string s1 = "hellooabcdaabe";
int i = s1.IndexOf('l'); Console.WriteLine(i); Console.WriteLine(s1.IndexOf("ab")); Console.WriteLine(s1.LastIndexOf('l')); string s2 = s1.Substring(4); Console.WriteLine(s2); Console.WriteLine(s1.Substring(4,3));
案例获取一个文件名的名称和扩展名部分:
string filename = "[ADS-118]林志aaaaaa玲.avi";//
int dotIndex = filename.IndexOf('.');//3
string name = filename.Substring(0, dotIndex);
Console.WriteLine(name);
string ext = filename.Substring(dotIndex + 1); Console.WriteLine(ext);
练习:从http://www.rupeng.com:8090/a.htm获得域名、端口号
------------------------------------------------
第 3 节 String常用方法3
String ToLower():把字符串变成小写(获得一个新的全小写的字符串返回);String ToUpper():把字符串变成大写
String Replace(char oldChar,char newChar):用新的字符去替换指定的旧字符,返回一个新的字符串;String Replace(String oldStr,String newStr):用新的字符串去替换指定的旧字符串
String是不可变的(是指这个字符串对象不可改变,无法修改字符串的内容),因此上面的操作都是生成新的字符串对象,要用返回值去取新的字符串。
string s1="Hello"; s1.ToLower(); //s1还是“Hello” ;
只有重新指向才会改变:s1=s1.ToLower();
案例:给一个全班数学考试成绩的字符串“50, 80,33,58,99, 82”,成绩用逗号分隔,有的成绩中可能有空格,有的地方逗号是英文、有的逗号是中文。统计班级的平均分。
------------------------------------------------
第 4 节 String常用方法4
String trim():去除字符串两端空格, Trim(params char[] trimChars)去掉两端的给定字符。 TrimEnd、 TrimStart
String[] Split(...):重载方法很多,字符串按照分隔符切割。
要求:写代码就是精益求精,在不降低可读性的情况下,不断精减代码。
练习:成绩字符串“34,45,65, 54,76,43,”,求平均分。
int/int=int; int*1.0/int=double;
------------------------------------------------
第 5 节 String常用方法5
string静态方法:
bool IsNullOrEmpty(string value):判断字符串是否为null或者是空字符串;
bool Equals(string a, string b, StringComparison. OrdinalIgnoreCase): StringComparison. OrdinalIgnoreCase不区分大小写比较。案例:验证码
string Join(string separator, params string[] value)把一个数组(集合)用分隔符separator连接为一个字符串。
if(str==null||str.Length<=0) //短路
记忆方法:使用案例记忆知识点(知识点的使用场景),而不是单独死记知识点。
------------------------------------------------
第 6 节 案例:小冰聊天机器人
功能:
1. 你好 好你妹
2.名字 我叫小冰
3.男的 女的 人家是女孩子
4.男朋友 人家还小,不考虑
5.其他 呵呵
6.唱(歌):播放音乐 SoundPlayer类
解决安全:属性 通用属性 当前选择内容
keyPress事件中:
txtRecord.AppendText(Convert.ToString(e.KeyChar));
//我在几点几分说什么内容
//小冰回复什么
e.keyChar=='\r'
------------------------------------------------
第 7 节 案例:表白神器
用Timer,设定Interval(每隔多少毫秒调用一次Tick事件)。
设一个100ms执行一次的定时器,从预定义的“全部表白文本”,每次取在当前文本框文本的长度,然后从“全部表白文本”取第“当前文本框文本的长度”个字符插入到TextBox(设定为多行、Append()附加),当输出完毕Timer.Enabled=false停止定时器。
Timer
------------------------------------------------
第 8 节 StringBuilder
1、使用反编译发现
String s7="111"+"222"+"333"+"444"+"555"
会被优化为 String s7 = "111222333444555";
但是String s6 = s1 + s2 + s3 + s4 + s5;就没那么幸运了,每次+都会生成一个String对象,当连接字符串比较多的时候就会产生临时字符串对象。
2、使用StringBuilder拼接字符串则不会有临时字符串对象的问题:
StringBuilder sb = new StringBuilder();
sb.Append(s1);
sb.Append(s2);
sb.Append(s3);
因为Append方法把this返回了,还可以sb.Append(s1).Append(s2).Append(s3);
最后使用String s = sb.ToString()一次性生成拼接结果字符串即可
sb.AppendLine(33);
using System;
using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace CommonClassTest2 { class Program { static void Main(string[] args) { /* string s1 = "aaa" + +"aaaaa"+"bbb"; Console.WriteLine(s1); */ string s1 = "aaa"; string s2 = "bbb"; string s3 = "ccc"; string s4 = "ddd"; string s5 = "afadsf"; string s6 = s1 + s2 + s3 + s4 + s5; StringBuilder sb = new StringBuilder(); /* sb.Append(s1); sb.Append(s2); sb.Append(s3); sb.Append(s4); sb.Append(s5); sb.Append(33);*/ sb.Append(s1).Append(s2).Append(s3).Append(s4).Append(s5); sb.AppendLine("hello"); sb.AppendLine("afasdfads"); string s7 = sb.ToString(); Console.WriteLine(s7); Person p1 = new Person(); p1.Eat().Sleep().Dota();//链式编程 Jquery Console.ReadKey(); } } class Person { public Person Eat() { Console.WriteLine("吃饭"); return this; } public Person Sleep() { Console.WriteLine("睡觉"); return this; } public Person Dota() { Console.WriteLine("打Dota"); return this; } } }
------------------------------------------------
第 9 节 可空的int(值类型)
int等是值类型,不能为null。有时想表达“不知道数字是多少”的时候,用int任何值表示都不合适。
C#中可以用“int?”表示“可空的int”。注意类型转换:
int? i1=5;
if(i1!=null)
{
int i= (int)i1;
}
也可以通过i1.HasValue判断是否为null、i1.Value来获得值。
int? i = null;
int? i2 = 3; if (i == null) { Console.WriteLine("i为null"); } if (i2 != null)//i2.HasValue { //i2++; i2 = i2 + 3; //int i3 = i2;//把可能为null的int?赋值给 //一定不为null的int int i3 = (int)i2;//i2.Value Console.WriteLine(i2); } long? l = null;
------------------------------------------------
第 10 节 案例:LED时钟
.Net使用DateTime类表示时间数据类型。DateTime属于结构体,因此也是值类型。
DateTime.Now当前时间;DateTime.Today当前日期。
可以通过Year、Month、Hour 等属性得到日期的年、月、小时等部分;也可以用构造函数根据给定的时间创建一个对象。
DateTime dt = DateTime.Now;
Console.WriteLine(dt);
Console.WriteLine(DateTime.Today);
DateTime dt2 = new DateTime(2019, 9, 10); Console.WriteLine(dt2); Console.WriteLine(dt.Year); Console.WriteLine(dt.DayOfYear); Console.WriteLine(dt.Second);
练习1:LED时钟
练习2:实现整点报时“北京时间18点整”
练习3:把数字转换为中文金额数字 123 ->壹佰贰拾叁元整
------------------------------------------------
第 11 节 异常的概念和捕获
1、异常的根类为Exception。异常类一般都继承自Exception
2、异常的捕获
try
{
String s = null; s.ToString(); } catch (NullReferenceException ex) { Console.WriteLine("为空"+ex.Message); }
e就是发生异常的异常类对象,变量名只要不冲突就任意。
3、在异常处理中,一旦try里面有问题了。放弃try代码块中之后的代码,直接跳到catch里面执行。如果try代码后还有代码,则处理完catch后还会继续执行。
------------------------------------------------
第 12 节 try finally
4、多个异常的处理
try { int a = 10; int b = 0; Console.WriteLine(a / b); int[] arr = { 1, 2, 3 }; Console.WriteLine(arr[3]); } catch (DivideByZeroException ae) { Console.WriteLine("除数不能为0"); } catch (IndexOutOfRangeException ae) { Console.WriteLine("数组越界异常"); }
可以catch住父类异常,这样就可以抓住所有子类异常了,但是强烈不建议大家这样做,特别是不要没理由的catch(Exception ex)
如果不知道如何处理异常,就不要轻易的catch 。
5、好的异常处理习惯:
不要只是把异常catch住什么都不做或者只是打印一下,这不是正常的“异常处理”。
不知道怎么处理就不要catch,出错比“把错误藏起爱”好。这样以为“不会出错了”,其实是把异常“吃掉了”,会让程序陷入逻辑混乱状态,要科学合理的处理异常(以后经常用就明白了)。
try{
//有可能有问题代码
}catch(异常类型 异常变量){ //处理方式 }finally{ //无论“有可能有问题代码”是否出错都要执行的代码 }
finally中一般进行资源的回收等
可以只有try{}finally{},没有catch,一般发生在不知道如何处理异常的情况下,回收资源
如果不知道怎么处理,就不要catch。
不允许以下代码:
try{
//代码
}catch(Exception ex){ //垃圾代码,抓住异常后,是必须要处理掉的,而不是再抛出一个异常 throw ex; }
------------------------------------------------
第 13 节 File类(静态方法),对文件(夹)进行处理,System.IO;
File是静态类(无法被new)中的主要静态方法:
void Delete(string path):删除文件;
bool Exists(string path):判断文件是否存在;
string[] ReadAllLines(string path):将文本文件中的内容读取到string数组中;
string ReadAllText(string path):将文本文件读取为一个字符串
void WriteAllLines(string path, string[] contents):将string[]写入到文件中;
void WriteAllText(string path, string contents):将字符串contents写入到文件path中。
AppendAllText:向文件中附加内容;Copy复制文件;Move移动文件
/* if(File.Exists(@"d:\temp\a.pnproj")) { File.Delete(@"d:\temp\a.pnproj"); }*/ /* string[] lines = File.ReadAllLines(@"d:\temp\my.txt", Encoding.Default); for (int i = 0; i < lines.Length; i++) { Console.WriteLine("第"+i+"行:"+lines[i]); }*/ /* String s = File.ReadAllText(@"d:\temp\my.txt"); Console.WriteLine(s); */ // File.WriteAllText(@"d:\temp\test.txt", "如鹏网欢迎你"); //File.AppendAllText(@"d:\temp\test.txt", "afasfsafadsf");
------------------------------------------------
第 14 节 Directory类
CreateDirectory(string path):创建文件夹全路径
void Delete(string path, bool recursive):删除文件夹path, recursive表示是否也删除子文件及子文件夹。如果文件夹不为空, recursive=false,则抛异常;
bool Exists(string path):判断文件夹是否存在
EnumerateFiles、 EnumerateDirectories遍历文件和文件夹;
// Directory.CreateDirectory(@"d:\temp\a\b\c");
//Directory.Delete(@"d:\temp\");//目录=文件夹,只能删除空文件夹
//Directory.Delete(@"D:\temp\redissessiontest", true); //递归删除
IEnumerable<string> files1 =
//Directory.EnumerateFiles(@"d:\temp");
//Directory.EnumerateFiles(@"d:\temp","*.*",SearchOption.AllDirectories);
Directory.EnumerateFiles(@"d:\temp", "*.avi", SearchOption.AllDirectories); IEnumerator<string> filesEnum1 = files1.GetEnumerator(); while (filesEnum1.MoveNext())//在结果中向下移动一条 { Console.WriteLine(filesEnum1.Current);//获得当前结果 }
------------------------------------------------
第 15 节 FileStream写入
File类提供了读写文本文件的方法,但是对于大文件不能用它提供的方法,占内存,需要一种“流式处理”的方法。
.NET将IO操作(文件、网络等)简化成流模型Stream,是抽象类,网络、文件、加密等都是不同的子类,最常用的子类是FileStream,MemoryStream等。
在使用Stream的时候虽然可以写成:FileStream fs=new FileStream(……),但是Stream fs=new FileStream(……)更好,在使用的变量类型提供的操作能满足的前提下,尽可能使用父类、接口声明变量。
FileStream fs = new FileStream(@"d:\temp\1.txt",FileMode.Create);
byte[] bytes1 = Encoding.Default.GetBytes("如鹏网你好\r\n");
//任何数据都是以byte为单位写入的。GetBytes获得字符串的byte表示形式
fs.Write(bytes1,0,bytes1.Length); byte[] bytes2 = Encoding.Default.GetBytes("www.rupeng.com"); fs.Write(bytes2,0,bytes2.Length);//在上一个Write的结尾继续写入 fs.Close();//一定要用完了关闭
Stream写入的单位是byte(字节),char转换为byte时候,一个英文char转换为一个byte(对应的ASCII码),一个中文char转换为两个byte(*采用GBK编码时),试着输出bytes的长度。
采用Default、UTF8、UTF32得到的字符串的byte[]长度不一样,因此说明不同类型编码在计算机中存储的不一样。用什么编码写入就用什么编码读取,否则会有乱码的问题。
不要往C盘写,因为Win7、Win8默认普通程序没有权限读写C盘。
------------------------------------------------
第 16 节 FileStream资源正确的释放Dispose
如果发生异常,fs就不能正常close,fs用完必须Close;
资源回收最好用Dispose()方法。
可以用:
FileStream fs=null;//避免来不及创建就出异常了,必须初始化
try{
//fs有可能成为没有被赋值的变量
fs=new FileStream(.....);
......
} finally{if(fs!=null){fs.Dispose();}}
所有实现IDisposable接口的都可以调用Dispose()方法。
------------------------------------------------
第 17 节 using简化资源释放
using()using(){}
每次资源关闭都要写这么一堆代码,C#中提供了using语法,对于一个实现IDisposable接口的对象,进行资源释放。
定义一个实现了IDisposable接口的类:
using System;
using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace IOTest2 { class MyFileStream:IDisposable { public MyFileStream() { //throw new Exception("初始化出错"); } public void Write(int i) { throw new Exception("Write出错"); Console.WriteLine("写入了"+i); } public void Dispose() { Console.WriteLine("Dispose被调用了,开始释放资源,虽然没什么可释放的"); } } }
使用:
using (MyFileStream fs1 = new MyFileStream())
{
using (MyFileStream fs2 = new MyFileStream()) { fs2.Write(333); fs1.Write(5); } }
可以同时声明多个资源:
using (MyFile f1 = new MyFile())
using (MyFile f2 = new MyFile())
{
}
using其实就是编译器简化的try……finally操作,通过ILSpy反编译成IL可以看出来。
using只是try……finally,如果需要catch,只要catch就是了。
using作用域就是{}中,,using只是finally,如果要catch,还是要try catch。
------------------------------------------------
第 18 节 FileStream读取文件以及乱码问题
using (FileStream fs = new FileStream(@"D:\temp\1.txt", FileMode.Open))
{
byte[] bytes = new byte[4]; //fs.Read(bytes, 0, bytes.Length);//每次读取4个字节,下次Read的时候再读取最多4个byte //返回值为真正读取的字节数 int len; /* len = fs.Read(bytes, 0, bytes.Length); Console.WriteLine(len); len = fs.Read(bytes, 0, bytes.Length); Console.WriteLine(len); len = fs.Read(bytes, 0, bytes.Length); Console.WriteLine(len); */ //判断是否已经读到了最后 while ((len = fs.Read(bytes, 0, bytes.Length)) > 0) { //Console.WriteLine(len); //把byte数组转化为字符串 //string s = Encoding.Default.GetString(bytes); string s = Encoding.Default.GetString(bytes, 0, len); Console.WriteLine(s); } }
字节流(FileStream)不适合读取内容中包含文本的文档,容易造成数据错乱(byte[]中含有一半的汉字),要用后面讲的StreamReader。
------------------------------------------------
第 19 节 FileStream实现文件的拷贝
Stopwatch sw = new Stopwatch();
sw.Start();
using (Stream inStream =
new FileStream(@"d:\temp\DevCpp.zip", FileMode.Open)) using (Stream outStream = new FileStream(@"e:\temp\1.zip", FileMode.Create)) { //byte[] bytes = new byte[100];//100字节 //1024字节=1k,1024k=1m byte[] bytes = new byte[1024*50];//1M(一般在几M范围) //缓冲区(buffer)的大小:过小:降低速度;过大:占用内存 int len; while ((len = inStream.Read(bytes, 0, bytes.Length)) > 0) { outStream.Write(bytes, 0, len);//类似于GetString } } sw.Stop(); Console.WriteLine("拷贝完成,耗时" + sw.ElapsedMilliseconds+"毫秒");
------------------------------------------------
第 20 节 封装Copy流的方法并开发下载器
封装一个方法void copy(Stream inStream,Stream outStream,int bufferSize)用来把inStream复制到outStream中,
缓冲区大小为bufferSize。要检查参数合法性(是否为null,bufferSize是否在合理范围内)
再提供一个使用默认缓冲区大小的copy的重载,复习重载。
------------------------------------------------
第 21 节 StreamReader和StreamWriter
直接用Stream进行文本文件的读写会比较麻烦,因为要考虑文件的编码、中文字符等的问题。
StreamReader、StreamWriter是用来读写字符流(character stream)的类,会帮着自动处理麻烦的问题。
using (Stream outStream =
new FileStream(@"d:\temp\1.txt", FileMode.Create))
using(StreamWriter sw =
new StreamWriter(outStream,Encoding.Default)) { sw.Write("你好a如鹏网"); sw.WriteLine("hehe"); sw.WriteLine("1111"); }
using (Stream inStream = new FileStream(@"d:\temp\1.txt",
FileMode.Open))
using (StreamReader reader =
new StreamReader(inStream, Encoding.Default)) { /* string s = reader.ReadToEnd(); Console.Write(s);*/ /* string s1 = reader.ReadLine(); Console.WriteLine(s1); string s2 = reader.ReadLine(); Console.WriteLine(s2); */ string line; while ((line = reader.ReadLine()) != null) { Console.WriteLine(line); } }
编码:
由于历史原因,汉字等如何在计算机中以字节存储存在着多种标准,最学见的有GB2312(国家标准,表示汉字)、
GBK(GB2312的扩展,还能表示繁体字等)、UTF-8(国际标准),UTF-16等。
用什么编码保存就用什么编码读取,就不会乱码!
StreamWriter构造函数决定(为什么?)new StreamWriter(outStream,Encoding.UTF8).
读取的编码由StreamReader构造函数决定。
------------------------------------------------
第 22 节 泛型List
1、数组长度是固定的,List<T>可以动态增删内容。List<T>是泛型的,可以在声明的时候指定放什么类型的数据。
List<int> list = new List<int>();
list.Add(1);
list.Add(2);
list.AddRange(new int[] { 1, 2, 3, 4, 5, 6 });
list.AddRange(list);//另一个list
2、如何遍历?
for (int i = 0; i < list1.Count; i++)
{
int num = list1[i];
Console.WriteLine(num);
}
3、int[] nums = list.ToArray(); //List泛型集合可以转换为数组
List<string> listStr = new List<string>();
string[] str = listStr.ToArray();
------------------------------------------------
第 23 节 字典Dictionary
Dictionary<string, string> dict = new Dictionary<string, string>();
dict.Add("zs", "张三"); dict.Add("ls", "李四"); dict.Add("ww", "王五"); dic["ls"] = "小赵"; String s = dict["ww"]; dict.ContainsKey(); //<k,v>k是键的类型(根据谁查),v是值的类型(查什么) /* Dictionary<string, int> dict = new Dictionary<string, int>(); dict.Add("abc", 123);//往字典中放数据(k,v) dict.Add("aaa", 222); int i = dict["abc"];//根据key从字典中查数据 Console.WriteLine(i); Console.WriteLine(dict["aaa"]);*/ /* Dictionary<string, string> dict = new Dictionary<string, string>(); dict.Add("zs","张三"); dict.Add("ls", "李四"); // dict.Add("ls","李斯");// 如果key已经存在,则抛异常 dict["ls"] = "李斯";//如果不存在key,则添加;如果存在则替换 dict["ww"] = "王五"; string name = dict["ls"]; Console.WriteLine(dict.ContainsKey("ls")); Console.WriteLine(dict.ContainsKey("abc")); Console.WriteLine(name);
字典Dictionary 内部使用哈希算法
------------------------------------------------
第 24 节 案例:火星文翻译器
就是(类似)替换,两个数组长度一样
作业 :汉字拆字
------------------------------------------------
第 25 节 ForEach
注意:使用MoveNext()的方法讲解IEumerable只是在讲原理,实际开发中还是使用foreach
除了使用for遍历,实现了IEumerable接口的对象还可以使用foreach遍历:
string[] strs = { "fasdfa","fsadf","222"};
foreach (string s in strs) { Console.WriteLine(s); }
List<T>、 Dictionary<K,V> 等一切实现了IEnumerable接口的对象都可以:
Dictionary<string, object> dict = new Dictionary<string, object>();
dict["rupeng"] = 888; dict["sina"] = "hehe"; dict["baidu"] = true; foreach (KeyValuePair<string, object> kv in dict) { Console.WriteLine(kv.Key+"="+kv.Value); }
如鹏网:http://www.rupeng.com