C# 面向对象系列笔记(五) 完结
第五天
1、文件流
好处:因为File类在读写文件的时候,采取的是一次性进行读取,会对我们的内存造成很大的压力,所以说,我怕们在操作大文件的时候,采用文件流进行读写。
FileStream:操作字节的(常用)
StreamReader和StreamWriteLine: 操作字符的。
什么是文本:拖到记事本中还能够看得明白的文件就是文本文件
eg:使用FileStream来读取一个文本文件
//第一步:创建FileStream对象
//第一个参数:要操作的文件的路径
//第二个参数:指定打开文件的方式
//第三个参数:用来指定要对文件中数据的操作
using (FileStream fsRead = newFileStream(@"C:\Users\SpringRain\Desktop\接口特点.txt", FileMode.OpenOrCreate, FileAccess.Read))
{
//第二步:创建缓冲区的大小
byte[] buffer = newbyte[1024 * 1024 * 5];
//第三步开始读取
//返回的r代表缓冲区中实际有效的字节数
int r = fsRead.Read(buffer, 0, buffer.Length);
//第四步:从缓冲区中拿数据 字节数组--->字符串 GC
string str = Encoding.Default.GetString(buffer, 0, r);
Console.WriteLine(str);
===========================================================================
eg:FileStream实现文件的复制
staticvoid Main(string[] args)
{
string source = @"C:\Users\SpringRain\Desktop\2、使用FileStream读取数据.mp4";
string target = @"C:\Users\SpringRain\Desktop\新来哒.mp4";
CopyFile(source, target);
Console.WriteLine("复制成功");
Console.ReadKey();
}
staticvoid CopyFile(string source, string target)
{
//思路:先读取,再写入
//创建负责读取的流
using (FileStream fsRead = newFileStream(source, FileMode.OpenOrCreate, FileAccess.Read))
{
//创建负责写入的流
using (FileStream fsWrite = newFileStream(target, FileMode.OpenOrCreate, FileAccess.Write))
{
//创建缓冲区
byte[] buffer = newbyte[1024 * 1024 * 5];
//开始读取
while (true)
{
//读取 r是本次实际读取到的有效字节数
int r = fsRead.Read(buffer, 0, buffer.Length);
if (r == 0)//本次没有读取到任何数据 说明读完了
{
break;
}
//写入
fsWrite.Write(buffer, 0, r);
}
}
}
StreamReader和StreamWriteLine: 操作字符的。
//使用StreamReader来读取文件
using (StreamReader sr = newStreamReader(@"C:\Users\SpringRain\Desktop\接口特点.txt",Encoding.Default))
{
//表示只要没读取完毕就不停的读取
while(!sr.EndOfStream)
{
Console.WriteLine(sr.ReadLine());
}
//使用StreamWriter来写入数据
using (StreamWriter sw = newStreamWriter(@"C:\Users\SpringRain\Desktop\new.txt",true))
{
string str = "123123123";
sw.WriteLine(str);
}
Console.WriteLine("写入成功");
Console.ReadKey();
2、using 释放资源
我们将创建文件流对象程序写在using的小括号中,将操作写在大括号中
using会在程序结束之后自动帮助我们关闭,释放资源;用法: using()
{ }
3、对象初始化器 (在后面加个大括号进行快速赋值)
eg:
List<int> list = newList<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
4、自动属性
自动属性:封装着字段,让我们在设计类的时候,可以省略掉字段
自动属性=私有字段+普通属性
eg:
publicstring Name { get; set; }
publicint Age { get; set; }
publicchar Gender { get; set; }
5、部分类和密封类
部分类:类前加partial,能同时声明两个相同的类,能同时对这个类操作
eg:
partialclassPerson//部分类
{
int _age;
}
partialclassPerson
{
publicvoid Test()
{
_age = 19;
}
}
密封类: 类前加sealed,不允许被继承的类,但它可以继承继承别人
sealedclassPerson:PersonFather//密封类
6、序列化和反序列化
1> 序列化:就是将对象转换为二进制的字符;
2> 反序列化:将二进制转换为对象;
3> 目的:保存数据,传输数据
注意:我们在网络中传输数据,必须传输数据的二进制形式
如果一个对象想要被序列化或者反序列化,那么这个对象所在的类必须标记为可序列化 (类名前加上[Serializable])
类:
[Serializable]
classPerson
{
publicstring Name { get; set; }
publicint Age { get; set; }
publicchar Gender { get; set; }
}
序列化
2、准备对象
Person person = newPerson() { Name = "张三", Age = 18, Gender = '男' };
//3、开始序列化并且发送给客户端
using (FileStream fsWrite = newFileStream(@"C:\Users\SpringRain\Desktop\对象.txt", FileMode.OpenOrCreate, FileAccess.Write))
{
//创建序列化的对象
BinaryFormatter bf = newBinaryFormatter();
//调用函数帮助我们将对象转换为二进制
bf.Serialize(fsWrite, person);
}
Console.WriteLine("序列化成功");
------------------------------------------------------
//客户端拿到二进制后开始进行反序列化
Person person;
using (FileStream fsRead = newFileStream(@"C:\Users\SpringRain\Desktop\对象.txt", FileMode.OpenOrCreate, FileAccess.Read))
{
//创建反序列化对象
BinaryFormatter bf = newBinaryFormatter();
//开始反序列化
person = (Person)bf.Deserialize(fsRead);
}
Console.WriteLine(person.Name);
Console.WriteLine(person.Age);
Console.WriteLine(person.Gender);
Console.ReadKey();
}
7、接口 接口是一种规范。也是一种能力。
用法:
interface + 接口名称
eg:
interfaceIKouLan
{
void KouLan();
}
1> 只要一个类继承了一个接口,这个类必须实现这个接口中所有成员
2> 接口不能被实例化。(接口不能new,跟抽象类是一样的)因为创建对象也无意义
3> 接口中的成员不能”加访问符”,接口中的成员访问修饰符为public,不能修改类。
类中的成员默认是访问符是private(不能额外添加)
接口中默认的访问修饰符是public
4> 接口中的成员不能有任何实现(“光说不做”,只是定义了一组为实现的成员);
5> 接口中只能有方法,属性,索引器,事件,不能有“字段”和“构造函数”。
6> 接口并不能去继承一个类,而类可以继承接口(接口只能继承接口,而类既可以继承接口,也可以继承类)
接口和接口之间可以继承
7> 实现接口的子类必须实现该接口的全部成员
8> 一个类可以同时继承一个类并实现多个接口,如果一个字类同时继承了父类A,并实现了接口IA,那么语法上A必须写在IA的前面。
9>当一个抽象类实现接口的时候,需要子类去实现接口。
class MyClass:A,IA{},因为类是单继承的。
显示实现接口的目的:解决方法的重名问题
什么时候显示的去实现接口:
当继承的接口中的方法和参数一模一样的时候,要使用显示的实现接口。
eg:
classPerson : I1
{
publicint Test(int n)
{
Console.WriteLine("我是Person的Test函数");
return 100;
}
publicvoid Test(int n)
{ }
voidI1.Test()
{
Console.WriteLine("我是I1接口中的方法");
}
}
interfaceI1
{
int Test(int n);
}
8、设计模式
设计模式帮助我们解决了一系列固定的问题。
简单工厂设计模式:
//简单工厂设计模式的核心根据用户的输入返回父类笔记本
eg:
//1、不打折 2、95折 3、85折 4、买300送50 5、买500送100
Console.WriteLine("您本次总共消费800元,请选择打折方式");
Console.WriteLine("1、不打折 2、95折 3、85折 4、买300送50 5、买500送100");
double money = 800;
string input = Console.ReadLine();
//根据用户选择的打折方式计算应该给多少钱
DzFather dz = GetDZ(input);
if (dz != null)
{
double realMoney = dz.GetMoney(money);
Console.WriteLine("您打折前应付{0}元,打折后应付{1}元", money, realMoney);
}
else
{
Console.WriteLine("没有这种打折方式");
}
Console.ReadKey();
}
staticDzFather GetDZ(string input)
{
DzFather dz = null;
switch (input)
{
case"1":
dz = newNoDz();
break;
case"2":
dz = newDzRate(0.95);
break;
case"3":
dz = newDzRate(0.85);
break;
case"4":
dz = newDzMN(300, 50);
break;
case"5":
dz = newDzMN(500, 100);
break;
}
return dz;
}
}
abstractclassDzFather
{
//根据打折前的总价钱返回打折后的总价钱
publicabstractdouble GetMoney(double totalMoney);
}
classNoDz : DzFather
{
publicoverridedouble GetMoney(double totalMoney)
{
return totalMoney;
}
}
classDzRate : DzFather
{
//折扣率
publicdouble Rate
{
get;
set;
}
//传入折扣率
public DzRate(double rate)
{
this.Rate = rate;
}
publicoverridedouble GetMoney(double totalMoney)
{
return totalMoney * this.Rate;
}
}
classDzMN : DzFather
{
publicdouble M { get; set; }//买的钱
publicdouble N { get; set; }//送的钱
public DzMN(double m, double n)
{
this.M = m;
this.N = n;
}
//300 50 700
publicoverridedouble GetMoney(double totalMoney)
{
if (totalMoney > this.M)
{
//怎么送钱
return totalMoney - (int)(totalMoney / this.M) * this.N;
}
else
{
return totalMoney;
}
}
}
9、MD5加密
//获得MD5对象
MD5 md5 = MD5.Create();
//由于加密的方法需要字节数组所以将要加密的字符串转换成字节数组
byte[] buffer = Encoding.Default.GetBytes(str);
//调用函数进行加密返回加密好的字节数组
byte[] md5Buffer = md5.ComputeHash(buffer);
//ToString() GetString() 23 43 56 我爱你
//把字符串中每个元素都进行ToString() 累加成一个字符串返回
string result = string.Empty;//""
for (int i = 0; i < md5Buffer.Length; i++)
{
result += md5Buffer[i].ToString("x2");//ToString("0.00")
}
return result;
}
第五天
1、文件流
好处:因为File类在读写文件的时候,采取的是一次性进行读取,会对我们的内存造成很大的压力,所以说,我怕们在操作大文件的时候,采用文件流进行读写。
FileStream:操作字节的(常用)
StreamReader和StreamWriteLine: 操作字符的。
什么是文本:拖到记事本中还能够看得明白的文件就是文本文件
eg:使用FileStream来读取一个文本文件
//第一步:创建FileStream对象
//第一个参数:要操作的文件的路径
//第二个参数:指定打开文件的方式
//第三个参数:用来指定要对文件中数据的操作
using (FileStream fsRead = newFileStream(@"C:\Users\SpringRain\Desktop\接口特点.txt", FileMode.OpenOrCreate, FileAccess.Read))
{
//第二步:创建缓冲区的大小
byte[] buffer = newbyte[1024 * 1024 * 5];
//第三步开始读取
//返回的r代表缓冲区中实际有效的字节数
int r = fsRead.Read(buffer, 0, buffer.Length);
//第四步:从缓冲区中拿数据 字节数组--->字符串 GC
string str = Encoding.Default.GetString(buffer, 0, r);
Console.WriteLine(str);
===========================================================================
eg:FileStream实现文件的复制
staticvoid Main(string[] args)
{
string source = @"C:\Users\SpringRain\Desktop\2、使用FileStream读取数据.mp4";
string target = @"C:\Users\SpringRain\Desktop\新来哒.mp4";
CopyFile(source, target);
Console.WriteLine("复制成功");
Console.ReadKey();
}
staticvoid CopyFile(string source, string target)
{
//思路:先读取,再写入
//创建负责读取的流
using (FileStream fsRead = newFileStream(source, FileMode.OpenOrCreate, FileAccess.Read))
{
//创建负责写入的流
using (FileStream fsWrite = newFileStream(target, FileMode.OpenOrCreate, FileAccess.Write))
{
//创建缓冲区
byte[] buffer = newbyte[1024 * 1024 * 5];
//开始读取
while (true)
{
//读取 r是本次实际读取到的有效字节数
int r = fsRead.Read(buffer, 0, buffer.Length);
if (r == 0)//本次没有读取到任何数据 说明读完了
{
break;
}
//写入
fsWrite.Write(buffer, 0, r);
}
}
}
StreamReader和StreamWriteLine: 操作字符的。
//使用StreamReader来读取文件
using (StreamReader sr = newStreamReader(@"C:\Users\SpringRain\Desktop\接口特点.txt",Encoding.Default))
{
//表示只要没读取完毕就不停的读取
while(!sr.EndOfStream)
{
Console.WriteLine(sr.ReadLine());
}
//使用StreamWriter来写入数据
using (StreamWriter sw = newStreamWriter(@"C:\Users\SpringRain\Desktop\new.txt",true))
{
string str = "123123123";
sw.WriteLine(str);
}
Console.WriteLine("写入成功");
Console.ReadKey();
2、using 释放资源
我们将创建文件流对象程序写在using的小括号中,将操作写在大括号中
using会在程序结束之后自动帮助我们关闭,释放资源;用法: using()
{ }
3、对象初始化器 (在后面加个大括号进行快速赋值)
eg:
List<int> list = newList<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
4、自动属性
自动属性:封装着字段,让我们在设计类的时候,可以省略掉字段
自动属性=私有字段+普通属性
eg:
publicstring Name { get; set; }
publicint Age { get; set; }
publicchar Gender { get; set; }
5、部分类和密封类
部分类:类前加partial,能同时声明两个相同的类,能同时对这个类操作
eg:
partialclassPerson//部分类
{
int _age;
}
partialclassPerson
{
publicvoid Test()
{
_age = 19;
}
}
密封类: 类前加sealed,不允许被继承的类,但它可以继承继承别人
sealedclassPerson:PersonFather//密封类
6、序列化和反序列化
1> 序列化:就是将对象转换为二进制的字符;
2> 反序列化:将二进制转换为对象;
3> 目的:保存数据,传输数据
注意:我们在网络中传输数据,必须传输数据的二进制形式
如果一个对象想要被序列化或者反序列化,那么这个对象所在的类必须标记为可序列化 (类名前加上[Serializable])
类:
[Serializable]
classPerson
{
publicstring Name { get; set; }
publicint Age { get; set; }
publicchar Gender { get; set; }
}
序列化
2、准备对象
Person person = newPerson() { Name = "张三", Age = 18, Gender = '男' };
//3、开始序列化并且发送给客户端
using (FileStream fsWrite = newFileStream(@"C:\Users\SpringRain\Desktop\对象.txt", FileMode.OpenOrCreate, FileAccess.Write))
{
//创建序列化的对象
BinaryFormatter bf = newBinaryFormatter();
//调用函数帮助我们将对象转换为二进制
bf.Serialize(fsWrite, person);
}
Console.WriteLine("序列化成功");
------------------------------------------------------
//客户端拿到二进制后开始进行反序列化
Person person;
using (FileStream fsRead = newFileStream(@"C:\Users\SpringRain\Desktop\对象.txt", FileMode.OpenOrCreate, FileAccess.Read))
{
//创建反序列化对象
BinaryFormatter bf = newBinaryFormatter();
//开始反序列化
person = (Person)bf.Deserialize(fsRead);
}
Console.WriteLine(person.Name);
Console.WriteLine(person.Age);
Console.WriteLine(person.Gender);
Console.ReadKey();
}
7、接口 接口是一种规范。也是一种能力。
用法:
interface + 接口名称
eg:
interfaceIKouLan
{
void KouLan();
}
1> 只要一个类继承了一个接口,这个类必须实现这个接口中所有成员
2> 接口不能被实例化。(接口不能new,跟抽象类是一样的)因为创建对象也无意义
3> 接口中的成员不能”加访问符”,接口中的成员访问修饰符为public,不能修改类。
类中的成员默认是访问符是private(不能额外添加)
接口中默认的访问修饰符是public
4> 接口中的成员不能有任何实现(“光说不做”,只是定义了一组为实现的成员);
5> 接口中只能有方法,属性,索引器,事件,不能有“字段”和“构造函数”。
6> 接口并不能去继承一个类,而类可以继承接口(接口只能继承接口,而类既可以继承接口,也可以继承类)
接口和接口之间可以继承
7> 实现接口的子类必须实现该接口的全部成员
8> 一个类可以同时继承一个类并实现多个接口,如果一个字类同时继承了父类A,并实现了接口IA,那么语法上A必须写在IA的前面。
9>当一个抽象类实现接口的时候,需要子类去实现接口。
class MyClass:A,IA{},因为类是单继承的。
显示实现接口的目的:解决方法的重名问题
什么时候显示的去实现接口:
当继承的接口中的方法和参数一模一样的时候,要使用显示的实现接口。
eg:
classPerson : I1
{
publicint Test(int n)
{
Console.WriteLine("我是Person的Test函数");
return 100;
}
publicvoid Test(int n)
{ }
voidI1.Test()
{
Console.WriteLine("我是I1接口中的方法");
}
}
interfaceI1
{
int Test(int n);
}
8、设计模式
设计模式帮助我们解决了一系列固定的问题。
简单工厂设计模式:
//简单工厂设计模式的核心根据用户的输入返回父类笔记本
eg:
//1、不打折 2、95折 3、85折 4、买300送50 5、买500送100
Console.WriteLine("您本次总共消费800元,请选择打折方式");
Console.WriteLine("1、不打折 2、95折 3、85折 4、买300送50 5、买500送100");
double money = 800;
string input = Console.ReadLine();
//根据用户选择的打折方式计算应该给多少钱
DzFather dz = GetDZ(input);
if (dz != null)
{
double realMoney = dz.GetMoney(money);
Console.WriteLine("您打折前应付{0}元,打折后应付{1}元", money, realMoney);
}
else
{
Console.WriteLine("没有这种打折方式");
}
Console.ReadKey();
}
staticDzFather GetDZ(string input)
{
DzFather dz = null;
switch (input)
{
case"1":
dz = newNoDz();
break;
case"2":
dz = newDzRate(0.95);
break;
case"3":
dz = newDzRate(0.85);
break;
case"4":
dz = newDzMN(300, 50);
break;
case"5":
dz = newDzMN(500, 100);
break;
}
return dz;
}
}
abstractclassDzFather
{
//根据打折前的总价钱返回打折后的总价钱
publicabstractdouble GetMoney(double totalMoney);
}
classNoDz : DzFather
{
publicoverridedouble GetMoney(double totalMoney)
{
return totalMoney;
}
}
classDzRate : DzFather
{
//折扣率
publicdouble Rate
{
get;
set;
}
//传入折扣率
public DzRate(double rate)
{
this.Rate = rate;
}
publicoverridedouble GetMoney(double totalMoney)
{
return totalMoney * this.Rate;
}
}
classDzMN : DzFather
{
publicdouble M { get; set; }//买的钱
publicdouble N { get; set; }//送的钱
public DzMN(double m, double n)
{
this.M = m;
this.N = n;
}
//300 50 700
publicoverridedouble GetMoney(double totalMoney)
{
if (totalMoney > this.M)
{
//怎么送钱
return totalMoney - (int)(totalMoney / this.M) * this.N;
}
else
{
return totalMoney;
}
}
}
------------------------------------------------------
第六天
1.MD5加密
//获得MD5对象
MD5 md5 = MD5.Create();
//由于加密的方法需要字节数组所以将要加密的字符串转换成字节数组
byte[] buffer = Encoding.Default.GetBytes(str);
//调用函数进行加密返回加密好的字节数组
byte[] md5Buffer = md5.ComputeHash(buffer);
//ToString() GetString() 23 43 56 我爱你
//把字符串中每个元素都进行ToString() 累加成一个字符串返回
string result = string.Empty;//""
for (int i = 0; i < md5Buffer.Length; i++)
{
result += md5Buffer[i].ToString("x2");//ToString("0.00")
}
return result;
}