C#自学笔记_012_Real(File类、文件流、多态、简单工厂设计模式)
一、File类
1、编码与解码
//一、file类
//1、读取txt文件中的字节(编码基础知识)
string str = @"E:\C#learningfile\Csharp012\春晓.txt";
byte[] byter = File.ReadAllBytes(str);
//将数组中的每一个元素都要按照我们制定的编码格式解码成字符串
//编码方式:UTF-8(国际通用) GB2312(简体中文) GBK(简体中文加繁体中文) ASCII Unicode(国际通用,包含UTF-8)
string s = Encoding.GetEncoding("UTF-8").GetString(byter);
//储存数据的编码方式需要和打开所用的编码方式保持一致。
Console.WriteLine(s);
2、向txt文件写入内容
//2、写入数据或字符串
string str = @"E:\C#learningfile\Csharp012\春晓.txt";
string str1 = "锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦。";
//需要将造富川转换成字节数组
byte[] byter1 = Encoding.Default.GetBytes(str1);
File.WriteAllBytes(str, byter1);//注意:浙江覆盖掉原来文件的所有内容
Console.WriteLine("写入成功!!");
二、绝对路径和相对路径
1、概念
绝对路径:通过给定的这个路径,可以直接能在我们电脑中找到这个文件
相对路径:文件相对于应用程序的路径
在开发中尽量使用相对路径
三、List泛型集合
//4、List泛型集合
//创建泛型集合对象
List<int> list = new List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
list.Add(4);
list.AddRange(new int[] {1,2,3,4,5,6,7,8 });
list.AddRange(list);
//可以将泛型集合对象转换成一个数组
int[] nums = list.ToArray();
//也可以将数组转换成泛型集合
List<int> listTwo = nums.ToList();
for (int i = 0; i < list.Count; i++)
{
Console.WriteLine(listTwo[i]);
}
四、装箱与拆箱
装箱:就是将值类型转换成引用类型
拆箱:将引用类型转换成值类型
注意:看两种类型是否发生了装箱或者拆箱,要看这两种类型是否存在继承关系
如:
//这个地方没有发生任意类型的装箱或者拆箱
string str = "123";
int n1 = Convert.ToInt32(str);
系统总应该避免出现装箱与拆箱,因为装箱与拆箱会浪费更多的时间。
五、小练习
//练习1:讲一个数组中的奇数放大一个集合中,偶数放在另一个集合中
//最终将两个集合放在同一个集合中,并且奇数显示在左边,偶数显示在邮编
int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 };
List<int> list1 = new List<int>();
List<int> list2 = new List<int>();
for (int i = 0; i < nums.Length; i++)
{
if (nums[i] % 2 == 0)
{
list1.Add(nums[i]);
}
else
{
list2.Add(nums[i]);
}
}
for (int i = 0; i < list1.Count; i++)
{
Console.WriteLine("list1[{0}] = {1}", i, list1[i]);
}
for (int i = 0; i < list2.Count; i++)
{
Console.WriteLine("list2[{0}] = {1}", i, list2[i]);
}
List<int> list3 = new List<int>();
list3.AddRange(list2);
list3.AddRange(list1);
Console.WriteLine(string.Join("、", list3));
//练习2:提示用户输入一个字符串,通过foreach循环将用户输入的字符串赋值给一个字符数组
Console.WriteLine("请输入一个字符串");
string str = Console.ReadLine();
char[] chs = new char[str.Length];
//char[] chs = str.ToCharArray();
int i = 0;
foreach (var item in str)
{
chs[i] = item;
i++;
}
for (int j = 0; j < chs.Length; j++)
{
Console.WriteLine(chs[j]);
}
//练习3:统计 Welcome to China中每个字符出现的次数,不考虑大小写
string str = "Welcome to China";
Dictionary<char, int> dic = new Dictionary<char, int>();
for (int i = 0; i < str.Length; i++)
{
if (str[i] == ' ')
{
continue;
}
if (!dic.ContainsKey(str[i]))
{
dic.Add(str[i], 1);
}
else
{
dic[str[i]]++;
}
}
foreach (KeyValuePair<char, int> kv in dic)
{
Console.WriteLine("{0}-----{1}", kv.Key, kv.Value);
}
六、文件流
1、
FileStream 操作字节的(啥文件都能操作) 对文件数据一点一点的去读入,对内存压力大大减小。
StreamReader和StreamWriter 操作字符的(主要操作大型文本文件)
//6、文件流
//(1)FileStream(用来操作字节)
//创建FileStream对象
FileStream fsRead = new FileStream(@"E:\C#learningfile\Csharp012\春晓.txt", FileMode.OpenOrCreate, FileAccess.Read);
byte[] buffer = new byte[1024 * 1024 * 5];
//返回本次实际读取的有效字节数
int r = fsRead.Read(buffer, 0, buffer.Length);
//将字节数组中每一个元素按顺序制定的编码格式解码成字符串
string s = Encoding.Default.GetString(buffer, 0, r);
//关闭文件流
fsRead.Close();
//释放文件流做占用的资源
fsRead.Dispose();
Console.WriteLine(s);
//(2)FIleStream来写入数据
using (FileStream fsWrite = new FileStream(@"E:\C#learningfile\Csharp012\春晓.txt", FileMode.OpenOrCreate, FileAccess.Write))
{
string str = "我把你覆盖掉了吗?";
byte[] buffer = Encoding.Default.GetBytes(str);
fsWrite.Write(buffer, 0, buffer.Length);
}
Console.WriteLine("写入OK。");
2、练习
//小练习:赋值一个媒体文件到指定位置
//思路:就是先将要赋值的多媒体文件读取出来,然后再写入到制定的位置
string source = @"E:\C#learningfile\Csharp012\金刚川预告片.mp4";
string target = @"E:\C#learningfile\Csharp012\new.mp4";
Program.CopyFile(source,target);
Console.WriteLine("复制成功!!!");
定义一个复制文件的函数:
public static void CopyFile(string source, string target)
{
//创建一个负责读取的文件流
using (FileStream fsRead = new FileStream(source, FileMode.OpenOrCreate, FileAccess.Read))
{
//创建一个负责写入发的文件流
using (FileStream fsWrite = new FileStream(target, FileMode.OpenOrCreate, FileAccess.Write))
{
byte[] buffer = new byte[1024 * 1024 * 5];
//以为问价可能比较大,所以需要协议跟循环进行循环读取
while (true)
{
//返回本次读取的实际字节数
int r = fsRead.Read(buffer, 0, buffer.Length);
if (r == 0)
{
break;
}
fsWrite.Write(buffer, 0, r);
}
}
}
}
3、StreamReader和StreamWriter
//(2)StreamReader
using (StreamReader sr = new StreamReader(@"E:\C#learningfile\Csharp012\春晓.txt", Encoding.Default))
{
while (!sr.EndOfStream) //EndOfStream用来判断是否读到文件流结尾
{
Console.WriteLine(sr.ReadLine()); //.ReadLine()函数用来刦一行字符
}
}
//(3)StreamWriter
using (StreamWriter sw = new StreamWriter(@"E:\C#learningfile\Csharp012\春晓.txt", true))
{
sw.Write("\n飞流直下三千尺,疑是银河落九天?");
Console.WriteLine("写入成功!!!");
}
七、***多态
1、概念
让一个对象能够呈现出多种状态(类型)
2、实现多态的手段三种:
(1)虚方法
步骤:
1)将父类的方法标记为虚方法,使用关键字virtual,这个函数可以被子类重新写一遍。
2)在子类上使用override关键字
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Csharp012Pro
{
class Program
{
static void Main(string[] args)
{
//***多态***
//概念:让一个对象能够表现出多种状态(类型)
//实现多态的手段: 虚方法,抽象类,接口
Student s1 = new Student("张三");
Student s2 = new Student("李四");
Teacher t1 = new Teacher("王五");
Teacher t2 = new Teacher("赵六");
Police p1 = new Police("丁一");
Police p2 = new Police("孙二");
Doctor d1 = new Doctor("吴三");
Doctor d2 = new Doctor("孔七");
//虚方法:
Person[] pers = { s1, s2, t1, t2, p1, p2, d1, d2 };
for (int i = 0; i < pers.Length; i++)
{
(pers[i]).SayHello();
}
Console.ReadKey();
}
}
public class Person
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
public virtual void SayHello()
{
Console.WriteLine("我是人类。");
}
public Person(string name)
{
this.Name = name;
}
}
public class Student : Person
{
public Student(string name)
: base(name)
{
}
public override void SayHello()
{
Console.WriteLine("我是学生。我叫{0}", this.Name);
}
}
public class Teacher : Person
{
public Teacher(string name)
: base(name)
{
}
public override void SayHello()
{
Console.WriteLine("我是老师。我叫{0}", this.Name);
}
}
public class Police : Person
{
public Police(string name)
: base(name)
{
}
public override void SayHello()
{
Console.WriteLine("我是警察。我叫{0}", this.Name);
}
}
public class Doctor : Person
{
public Doctor(string name)
: base(name)
{
}
public override void SayHello()
{
Console.WriteLine("我是医生。我叫{0}", this.Name);
}
}
}
(2)抽象类
当父类的方法不知道如何去实现的时候,可以考虑将父类携程抽象类,将方法携程抽象方法
需要用到abstract关键字。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Csharp012plus
{
class Program
{
static void Main(string[] args)
{
//狗狗会汪汪汪的叫,小猫会喵喵喵的叫
//重要注意:抽象类不能创建对象!!!
Animal a = new Dog();
Animal b = new Cat();
a.Bark();
b.Bark();
Console.ReadKey();
}
}
public abstract class Animal
{
public abstract void Bark();
}
public class Dog : Animal
{
public override void Bark()
{
Console.WriteLine("狗狗会汪汪汪的叫。");
}
}
public class Cat : Animal
{
public override void Bark()
{
Console.WriteLine("小猫会喵喵喵的叫。");
}
}
}
特点:
(1)抽象成员必须标记为abstract,并且不能有任何实现。
(2)抽象成员必须在抽象类中(抽象类名和抽象成员都必须加abstract)。
(3)抽象类不能被实例化(不能用抽象类创建对象)。
(4)子类继承抽象类后,必须把父类中的所有抽象成员都重写(除非子类也是一个抽象类,否则不重写)。
(5)抽象成员的访问修饰符不能是private。
(6)在抽象类中可以包含实例成员,并且抽象类的实例成员可以不被子类实现。
(7)抽象类是有构造函数的,虽然不被实例化。
(8)如果父类的抽象方法中有参数,那么,继承这个抽象父类的子类在重写父类的方法的时候必须传入对应的参数。如果抽象父类的抽象方法中有返回值,那么子类在重写这个抽象方法的时候,也必须传入返回值。
(9)如果父类中方法有默认的实现,并且父类需要被实例化,这时可以考虑将父类定义成一个普通类,用虚方法来实现多态,如果父类中的方法没有默认实现,父类也不需要被实例化,则可以将该类定义成抽象类。
练习
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
//利用多态求矩形和圆形的面积和周长
Console.WriteLine("请输入圆形的半径:");
double r = Convert.ToDouble(Console.ReadLine());
Shape shape = new Circle(r);
double area = shape.GetArea();
double perimeter = shape.GetPerimeter();
Console.WriteLine("面积{0:0.00},周长{1:0.00}", area, perimeter);
Console.WriteLine("请输入矩形的长和宽:");
double width = Convert.ToDouble(Console.ReadLine());
double height = Convert.ToDouble(Console.ReadLine());
shape = new Square(height, width);
double area1 = shape.GetArea();
double perimeter1 = shape.GetPerimeter();
Console.WriteLine("面积{0},周长{1}", area1, perimeter1);
Console.ReadKey();
}
}
public abstract class Shape
{
public abstract double GetArea();
public abstract double GetPerimeter();
}
public class Circle : Shape
{
private double _r;
public double R
{
get { return _r; }
set { _r = value; }
}
public Circle(double r)
{
this.R = r;
}
public override double GetArea()
{
return (Math.PI * this.R * this.R);
}
public override double GetPerimeter()
{
return (2 * Math.PI * this.R);
}
}
public class Square : Shape
{
private double _height;
public double Height
{
get { return _height; }
set { _height = value; }
}
private double _width;
public double Width
{
get { return _width; }
set { _width = value; }
}
public Square(double height, double width)
{
this.Height = height;
this.Width = width;
}
public override double GetArea()
{
return (this.Height * this.Width);
}
public override double GetPerimeter()
{
return ((this.Width + this.Height) * 2);
}
}
}
练习:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Csharp012SE
{
class Program
{
static void Main(string[] args)
{
//写移动硬盘、U盘、MP3的类,使其能够插在电脑上读取并写入数据
MobieStorge ms = new Mp3();//new MobibeDisk();
Computer cpu = new Computer(ms);
cpu.CpuRead();
cpu.CpuWrite();
Console.ReadKey();
}
}
public abstract class MobieStorge
{
public abstract void Read();
public abstract void Write();
}
public class MobibeDisk : MobieStorge
{
public override void Read()
{
Console.WriteLine("移动硬盘正在读取数据");
}
public override void Write()
{
Console.WriteLine("移动硬盘正在写入数据");
}
}
public class UDisk : MobieStorge
{
public override void Read()
{
Console.WriteLine("U盘正在读取数据");
}
public override void Write()
{
Console.WriteLine("U盘正在写入数据");
}
}
public class Mp3 : MobieStorge
{
public override void Read()
{
Console.WriteLine("MP3正在读取数据");
}
public override void Write()
{
Console.WriteLine("MP3正在写入数据");
}
}
public class Computer
{
private MobieStorge _ms;
public MobieStorge Ms
{
get { return _ms; }
set { _ms = value; }
}
public Computer(MobieStorge ms)
{
this.Ms = ms;
}
public void CpuRead()
{
(this.Ms).Read();
}
public void CpuWrite()
{
(this.Ms).Write();
}
}
}
(3)接口(interface)
接口就是一个规范,能力
1)当子类需要继承多个父类的时候,考虑使用接口
2)语法格式:
[public] interface I(接口名)able
{
成员;
}
3)接口中的成员不允许添加访问修饰符,默认是public
4)接口成员中不允许有方法体的函数
5)接口中不允许有字段
6)接口中可以有自动属性
/// <summary>
/// 自动属性
/// </summary>
public int Age
{
get;
set;
}
public class Person
{
public void SayHello()
{
Console.WriteLine("我是人类。");
}
}
public class NBAplayer
{
public void KouLan()
{
Console.WriteLine("我可以扣篮。");
}
}
public class Student : Person, IKouLanAble
{
public void KouLam()
{
Console.WriteLine("我也可以扣篮。");
}
}
public interface IKouLanAble
{
void KouLam();
}
接口特点总结
1)借口是一种规范。
2)只要一个类继承了一个接口,这个类就必须实现这个借口的所有成员。
3)接口不能被实例化,即接口不能创建对象(不能new一个对象)
4)接口中的成员不能加访问修饰符,接口中的成员访问修饰符为public,不能修改。
(即默认修饰符为public,接口成员不能有任何事先,即光说不做,只是定义了一组未实现的成员)
5)接口中只能有方法、属性、索引器、时间,不能有“字段”和构造函数。
6)接口与接口之间可以继承,并且可以多继承。
7)接口不能去继承一个类,而类可以继承接口(接口只能继承于接口,而类既可以继承接口,也可以继承类)
8)实现接口的子类必须实现该接口的全部成员。
9)一个类可以同时继承一个类并实现多个接口,如果一个子类同时继承类父类A,并实现了接口IA,那么语法上A必须卸载IA前面,即:class MyClass : A : IA (因为类是单继承的。)
10)显示的实现接口的目的:解决方法的重名问题。
什么时候显示的实现接口:当继承的接口中的方法和参数一模一样的时候,要使用显示的实现接口。
11)当一个抽象类实现接口的时候,需要子类去实现接口。
显示的实现接口是为了解决重名问题
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Csharp012interface
{
class Program
{
static void Main(string[] args)
{
//显示的实现接口是为了解决重名问题
IFlyable fly = new Bird();
fly.Fly();
Bird bird = new Bird();
bird.Fly();
Console.ReadKey();
}
}
public class Bird : IFlyable
{
public void Fly()
{
Console.WriteLine("鸟会飞。");
}
//显示实现接口方法:
void IFlyable.Fly()
{
Console.WriteLine("我是接口的飞。");
}
}
public interface IFlyable
{
void Fly();
}
}
八、C#中的访问修饰符
public:公开的,公共的
private:私有的,只能在当前类的内部访问
protected:受保护的,只能在当前类的内部或者类的子类中访问
internal:只能在当前程序集中访问,(只能在当前项目红访问)但是在一个项目中,internal和public的的权限是一样的。
protected internal:protectedinternal
1)能够修饰类的访问修饰符只有两个:public 和 internal
2)可访问性不一致
子类的访问酸咸不能高于父类的访问权限,否则会暴露父类的成员
九、简单工厂设计模式
《大话设计模式》、《设计模式之禅》
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Csharp012T
{
class Program
{
static void Main(string[] args)
{
//****简单工厂模式****
//工厂生产四中笔记本电脑,需要用户进行选择,然后输出对应的笔记本电脑
Console.WriteLine("请输入您要购买的笔记本品牌:");
string brand = Console.ReadLine();
NoteBook nb = GetNoteBook(brand);
nb.SayHello();
Console.ReadKey();
}
/// <summary>
/// 简单工厂的核心:根据用户的输入创建对象赋值给父类
/// </summary>
/// <param name="brand"></param>
/// <returns></returns>
public static NoteBook GetNoteBook(string brand)
{
NoteBook nb = null;
switch (brand)
{
case "Acer":
nb = new Acer();
break;
case "Dell":
nb = new Dell();
break;
case "Ibm":
nb = new Ibm();
break;
case "Lenovo":
nb = new Lenovo();
break;
}
return nb;
}
}
public abstract class NoteBook
{
public abstract void SayHello();
}
public class Acer : NoteBook
{
public override void SayHello()
{
Console.WriteLine("我是宏碁笔记本");
}
}
public class Dell : NoteBook
{
public override void SayHello()
{
Console.WriteLine("我是戴尔笔记本");
}
}
public class Ibm : NoteBook
{
public override void SayHello()
{
Console.WriteLine("我是IBM笔记本");
}
}
public class Lenovo : NoteBook
{
public override void SayHello()
{
Console.WriteLine("我是联想笔记本");
}
}
}
十、值传递和地址传递
值类型在复制的时候,传递的是个值本身。
引用类型在复制的时候,传递的是对这个对象的引用
十一、序列化与反序列化
序列化:就是将对象转换为二进制
反序列化:就是将二进制转换为对象
作用:传输数据
实现:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
namespace Csharp012G
{
class Program
{
static void Main(string[] args)
{
要将p这个对象,传输给对方电脑
//Person p = new Person("张三", 20, '男');
p.Name = "张三";
p.Age = 21;
p.Gender = '男';
//using (FileStream fsWrite = new FileStream(@"E:\C#learningfile\Csharp012T\Csharp012G\111.txt", FileMode.OpenOrCreate, FileAccess.Write))
//{
// //开始序列化对象
// BinaryFormatter bf = new BinaryFormatter();
// bf.Serialize(fsWrite, p);
//}
//Console.WriteLine("序列化成功!");
//接收对方发送过来的二进制,反序列化成对象
Person p = null;
using (FileStream fsRead = new FileStream(@"E:\C#learningfile\Csharp012T\Csharp012G\111.txt", FileMode.OpenOrCreate, FileAccess.Read))
{
BinaryFormatter bf = new BinaryFormatter();
p = (Person)bf.Deserialize(fsRead);
}
Console.WriteLine(p.Name);
Console.WriteLine(p.Age);
Console.WriteLine(p.Gender);
Console.ReadKey();
}
}
[Serializable]
public class Person
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
private int _age;
public int Age
{
get { return _age; }
set { _age = value; }
}
private char _gender;
public char Gender
{
get { return _gender; }
set { _gender = value; }
}
public Person(string name, int age, char gender)
{
this.Name = name;
this.Age = age;
this.Gender = gender;
}
}
}
十二、部分类、密封类
1、部分类 (partial)
可以将好几个同名的类组成同一个类
//这两个类Person共同组成类Person
public partial class Person
{
//内容一;
}
public partial class Person
{
//内容二;
}
2、密封类(sealed)
密封类不能被继承,但是可以继承别人