上期回顾 - https://www.cnblogs.com/liu-jinxin/p/10831189.html

一、运算符重载

  您可以重定义或重载 C# 中内置的运算符。因此,程序员也可以使用用户自定义类型的运算符。重载运算符是具有特殊名称的函数,是通过关键字 operator 后跟运算符的符号来定义的。与其他函数一样,重载运算符有返回类型和参数列表。

  示例代码:

 1 using System;
 2 
 3 namespace OperatorOvlApplication
 4 {
 5    class Box
 6    {
 7       private double length;      // 长度
 8       private double breadth;     // 宽度
 9       private double height;      // 高度
10 
11       public double getVolume()
12       {
13          return length * breadth * height;
14       }
15       public void setLength( double len )
16       {
17          length = len;
18       }
19 
20       public void setBreadth( double bre )
21       {
22          breadth = bre;
23       }
24 
25       public void setHeight( double hei )
26       {
27          height = hei;
28       }
29       // 重载 + 运算符来把两个 Box 对象相加
30       public static Box operator+ (Box b, Box c)
31       {
32          Box box = new Box();
33          box.length = b.length + c.length;
34          box.breadth = b.breadth + c.breadth;
35          box.height = b.height + c.height;
36          return box;
37       }
38 
39    }
40 
41    class Tester
42    {
43       static void Main(string[] args)
44       {
45          Box Box1 = new Box();         // 声明 Box1,类型为 Box
46          Box Box2 = new Box();         // 声明 Box2,类型为 Box
47          Box Box3 = new Box();         // 声明 Box3,类型为 Box
48          double volume = 0.0;          // 体积
49 
50          // Box1 详述
51          Box1.setLength(6.0);
52          Box1.setBreadth(7.0);
53          Box1.setHeight(5.0);
54 
55          // Box2 详述
56          Box2.setLength(12.0);
57          Box2.setBreadth(13.0);
58          Box2.setHeight(10.0);
59 
60          // Box1 的体积
61          volume = Box1.getVolume();
62          Console.WriteLine("Box1 的体积: {0}", volume);
63 
64          // Box2 的体积
65          volume = Box2.getVolume();
66          Console.WriteLine("Box2 的体积: {0}", volume);
67 
68          // 把两个对象相加
69          Box3 = Box1 + Box2;
70 
71          // Box3 的体积
72          volume = Box3.getVolume();
73          Console.WriteLine("Box3 的体积: {0}", volume);
74          Console.ReadKey();
75       }
76    }
77 }
  执行结果:
  //Box1 的体积: 210
  //Box2 的体积: 1560
  //Box3 的体积: 5400

  可重载和不可重载运算符

    下表描述了 C# 中运算符重载的能力:

运算符描述
+, -, !, ~, ++, -- 这些一元运算符只有一个操作数,且可以被重载。
+, -, *, /, % 这些二元运算符带有两个操作数,且可以被重载。
==, !=, <, >, <=, >= 这些比较运算符可以被重载。
&&, || 这些条件逻辑运算符不能被直接重载。
+=, -=, *=, /=, %= 这些赋值运算符不能被重载。
=, ., ?:, ->, new, is, sizeof, typeof 这些运算符不能被重载。

    扩展示例:

  1 using System;
  2 
  3 namespace OperatorOvlApplication
  4 {
  5     class Box
  6     {
  7        private double length;      // 长度
  8        private double breadth;     // 宽度
  9        private double height;      // 高度
 10       
 11        public double getVolume()
 12        {
 13          return length * breadth * height;
 14        }
 15       public void setLength( double len )
 16       {
 17           length = len;
 18       }
 19 
 20       public void setBreadth( double bre )
 21       {
 22           breadth = bre;
 23       }
 24 
 25       public void setHeight( double hei )
 26       {
 27           height = hei;
 28       }
 29       // 重载 + 运算符来把两个 Box 对象相加
 30       public static Box operator+ (Box b, Box c)
 31       {
 32           Box box = new Box();
 33           box.length = b.length + c.length;
 34           box.breadth = b.breadth + c.breadth;
 35           box.height = b.height + c.height;
 36           return box;
 37       }
 38       
 39       public static bool operator == (Box lhs, Box rhs)
 40       {
 41           bool status = false;
 42           if (lhs.length == rhs.length && lhs.height == rhs.height 
 43              && lhs.breadth == rhs.breadth)
 44           {
 45               status = true;
 46           }
 47           return status;
 48       }
 49       public static bool operator !=(Box lhs, Box rhs)
 50       {
 51           bool status = false;
 52           if (lhs.length != rhs.length || lhs.height != rhs.height 
 53               || lhs.breadth != rhs.breadth)
 54           {
 55               status = true;
 56           }
 57           return status;
 58       }
 59       public static bool operator <(Box lhs, Box rhs)
 60       {
 61           bool status = false;
 62           if (lhs.length < rhs.length && lhs.height 
 63               < rhs.height && lhs.breadth < rhs.breadth)
 64           {
 65               status = true;
 66           }
 67           return status;
 68       }
 69 
 70       public static bool operator >(Box lhs, Box rhs)
 71       {
 72           bool status = false;
 73           if (lhs.length > rhs.length && lhs.height 
 74               > rhs.height && lhs.breadth > rhs.breadth)
 75           {
 76               status = true;
 77           }
 78           return status;
 79       }
 80 
 81       public static bool operator <=(Box lhs, Box rhs)
 82       {
 83           bool status = false;
 84           if (lhs.length <= rhs.length && lhs.height 
 85               <= rhs.height && lhs.breadth <= rhs.breadth)
 86           {
 87               status = true;
 88           }
 89           return status;
 90       }
 91 
 92       public static bool operator >=(Box lhs, Box rhs)
 93       {
 94           bool status = false;
 95           if (lhs.length >= rhs.length && lhs.height 
 96              >= rhs.height && lhs.breadth >= rhs.breadth)
 97           {
 98               status = true;
 99           }
100           return status;
101       }
102       public override string ToString()
103       {
104           return String.Format("({0}, {1}, {2})", length, breadth, height);
105       }
106    
107    }
108     
109    class Tester
110    {
111       static void Main(string[] args)
112       {
113         Box Box1 = new Box();          // 声明 Box1,类型为 Box
114         Box Box2 = new Box();          // 声明 Box2,类型为 Box
115         Box Box3 = new Box();          // 声明 Box3,类型为 Box
116         Box Box4 = new Box();
117         double volume = 0.0;   // 体积
118 
119         // Box1 详述
120         Box1.setLength(6.0);
121         Box1.setBreadth(7.0);
122         Box1.setHeight(5.0);
123 
124         // Box2 详述
125         Box2.setLength(12.0);
126         Box2.setBreadth(13.0);
127         Box2.setHeight(10.0);
128 
129        // 使用重载的 ToString() 显示两个盒子
130         Console.WriteLine("Box1: {0}", Box1.ToString());
131         Console.WriteLine("Box2: {0}", Box2.ToString());
132         
133         // Box1 的体积
134         volume = Box1.getVolume();
135         Console.WriteLine("Box1 的体积: {0}", volume);
136 
137         // Box2 的体积
138         volume = Box2.getVolume();
139         Console.WriteLine("Box2 的体积: {0}", volume);
140 
141         // 把两个对象相加
142         Box3 = Box1 + Box2;
143         Console.WriteLine("Box3: {0}", Box3.ToString());
144         // Box3 的体积
145         volume = Box3.getVolume();
146         Console.WriteLine("Box3 的体积: {0}", volume);
147 
148         //comparing the boxes
149         if (Box1 > Box2)
150           Console.WriteLine("Box1 大于 Box2");
151         else
152           Console.WriteLine("Box1 不大于 Box2");
153         if (Box1 < Box2)
154           Console.WriteLine("Box1 小于 Box2");
155         else
156           Console.WriteLine("Box1 不小于 Box2");
157         if (Box1 >= Box2)
158           Console.WriteLine("Box1 大于等于 Box2");
159         else
160           Console.WriteLine("Box1 不大于等于 Box2");
161         if (Box1 <= Box2)
162           Console.WriteLine("Box1 小于等于 Box2");
163         else
164           Console.WriteLine("Box1 不小于等于 Box2");
165         if (Box1 != Box2)
166           Console.WriteLine("Box1 不等于 Box2");
167         else
168           Console.WriteLine("Box1 等于 Box2");
169         Box4 = Box3;
170         if (Box3 == Box4)
171           Console.WriteLine("Box3 等于 Box4");
172         else
173           Console.WriteLine("Box3 不等于 Box4");
174 
175         Console.ReadKey();
176       }
177     }
178 }
179 //执行结果:
180 //Box1: (6, 7, 5)
181 //Box2: (12, 13, 10)
182 //Box1 的体积: 210
183 //Box2 的体积: 1560
184 //Box3: (18, 20, 15)
185 //Box3 的体积: 5400
186 //Box1 不大于 Box2
187 //Box1 小于 Box2
188 //Box1 不大于等于 Box2
189 //Box1 小于等于 Box2
190 //Box1 不等于 Box2
191 //Box3 等于 Box4
View Code

  

    operator 关键字用于在类或结构声明中声明运算符。运算符声明可以采用下列四种形式之一:

    public static result-type operator unary-operator ( op-type operand )
    public static result-type operator binary-operator ( op-type operand, op-type2 operand2 )
    public static implicit operator conv-type-out ( conv-type-in operand )
    public static explicit operator conv-type-out ( conv-type-in operand )
      •  result-type 运算符的结果类型。
      •  unary-operator 下列运算符之一:+ - ! ~ ++ — true false
      •  op-type 第一个(或唯一一个)参数的类型。
      •  operand 第一个(或唯一一个)参数的名称。
      •  binary-operator 其中一个:+ - * / % & | ^ << >> == != > < >= <=
      •  op-type2 第二个参数的类型。
      •  operand2 第二个参数的名称。
      •  conv-type-out 类型转换运算符的目标类型。
      •  conv-type-in 类型转换运算符的输入类型。

  注意:

    前两种形式声明了用户定义的重载内置运算符的运算符。并非所有内置运算符都可以被重载(请参见可重载的运算符)。op-type 和 op-type2 中至少有一个必须是封闭类型(即运算符所属的类型,或理解为自定义的类型)。例如,这将防止重定义整数加法运算符。

    后两种形式声明了转换运算符。conv-type-in 和 conv-type-out 中正好有一个必须是封闭类型(即,转换运算符只能从它的封闭类型转换为其他某个类型,或从其他某个类型转换为它的封闭类型)。

    运算符只能采用值参数,不能采用 ref 或 out 参数。

    C# 要求成对重载比较运算符。如果重载了==,则也必须重载!=,否则产生编译错误。同时,比较运算符必须返回bool类型的值,这是与其他算术运算符的根本区别。

    C# 不允许重载=运算符,但如果重载例如+运算符,编译器会自动使用+运算符的重载来执行+=运算符的操作。

    运算符重载的其实就是函数重载。首先通过指定的运算表达式调用对应的运算符函数,然后再将运算对象转化为运算符函数的实参,接着根据实参的类型来确定需要调用的函数的重载,这个过程是由编译器完成。

    任何运算符声明的前面都可以有一个可选的属性(C# 编程指南)列表。

二、接口

   1、接口的定义是指定一组函数成员而不实现成员的引用类型,其它类型和接口可以继承接口。接口主要有以下特点:

    (1)通过接口可以实现多重继承,C# 接口的成员不能有 public、protected、internal、private 等修饰符。原因很简单,接口里面的方法都需要由外面接口实现去实现方法体,那么其修饰符必然是 public。C# 接口中的成员默认是 public 的,java 中是可以加 public 的。

    (2)接口成员不能有 new、static、abstract、override、virtual 修饰符。有一点要注意,当一个接口实现一个接口,这2个接口中有相同的方法时,可用 new 关键字隐藏父接口中的方法。

     (3)接口中只包含成员的签名,接口没有构造函数,所有不能直接使用 new 对接口进行实例化。接口中只能包含方法、属性、事件和索引的组合。接口一旦被实现,实现类必须实现接口中的所有成员,除非实现类本身是抽象类。

    (4)C# 是单继承,接口是解决 C# 里面类可以同时继承多个基类的问题。

   代码示例:

 1 class Program
 2 {
 3     static void Main(string[] args)
 4     {
 5         IWorker james1 = new James1();
 6         IWorker james2 = new James2();
 7         james1.work("设计");
 8         james2.work("编程");
 9         //从这个例子我体会到了有接口的好处,可以想象如果又来了新的员工。
10         //如果不采用接口,而是每个员工都有一个单独的类,这样就会容易出错。
11         //如果有接口这种协议约束的话,那么只要实现了接口就肯定有接口里声明的方法,我们只需拿来调用。
12     }
13 }
14 public interface IWorker{ void work(string s); }
15 class James1 : IWorker
16 {
17     public void work(string s)
18     {
19         Console.WriteLine("我的名字是James1,我的工作是" +s);
20     }
21 }
22 class James2 : IWorker
23 {
24     public void work(string s)
25     {
26         Console.WriteLine("我的名字是James2,我的工作是"+s);
27     }
28 }
29 
30 //一个可以实例化接口的实例:
31 
32 class Program
33 {
34     static void Main(string[] args)
35     {
36         //C#中COM接口是可以实例化的,但其实这种写法是使接口“映射”到某一个类上,实际上创建的是这个类的实例。
37         IWorker worker = new IWorker();
38     }
39 }
40 [ComImport, CoClass(typeof(James1))]
41 [Guid("d60908eb-fd5a-4d3c-9392-8646fcd1edce")]
42 public interface IWorker{ void work(string s); }
43 //ComImport特性发生在tlbimp.exe导入COM类型类库的时候,生成的托管类型会标记有ComImport特性
44 //Guid特性是一个GUID标识,COM类型是用GUID来标识的。
View Code

  2、接口和抽象类的区别

    接口用于规范,抽象类用于共性。抽象类是类,所以只能被单继承,但是接口却可以一次实现多个。

    接口中只能声明方法,属性,事件,索引器。而抽象类中可以有方法的实现,也可以定义非静态的类变量。

    抽象类可以提供某些方法的部分实现,接口不可以。抽象类的实例是它的子类给出的。接口的实例是实现接口的类给出的。

    在抽象类中加入一个方法,那么它的子类就同时有了这个方法。而在接口中加入新的方法,那么实现它的类就要重新编写(这就是为什么说接口是一个类的规范了)。

    接口成员被定义为公共的,但抽象类的成员也可以是私有的、受保护的、内部的或受保护的内部成员(其中受保护的内部成员只能在应用程序的代码或派生类中访问)。

    此外接口不能包含字段、构造函数、析构函数、静态成员或常量。

    还有一点,我们在VS中实现接口时会发现有2个选项,一个是实现接口,一个是显示实现接口。实现接口就是我们平常理解的实现接口,而显示实现接口的话,实现的方法是属于接口的,而不是属于实现类的。

三、命名空间

  命名空间的设计目的是提供一种让一组名称与其他名称分隔开的方式。在一个命名空间中声明的类的名称与另一个命名空间中声明的相同的类的名称不冲突。

  1、定义命名空间:

    namespace namespace_name
    {
         // 代码声明
    }

  2、using关键字

    using 关键字表明程序使用的是给定命名空间中的名称。例如,我们在程序中使用 System 命名空间,其中定义了类 Console。我们可以只写:

      Console.WriteLine ("Hello there");  或者  System.Console.WriteLine("Hello there");

  3、嵌套命名空间

    可以使用点(.)运算符访问嵌套的命名空间的成员

    namespace namespace_name1 
    {
       // 代码声明
       namespace namespace_name2 
       {
         // 代码声明
       }
    }
四、预处理器指令

   在程序调试和运行上有重要的作用。比如预处理器指令可以禁止编译器编译代码的某一部分,如果计划发布两个版本的代码,即基本版本和有更多功能的企业版本,就可以使用这些预处理器指令来控制。在编译软件的基本版本时,使用预处理器指令还可以禁止编译器编译于额外功能相关的代码。另外,在编写提供调试信息的代码时,也可以使用预处理器指令进行控制。总的来说和普通的控制语句(if等)功能类似,方便在于预处理器指令包含的未执行部分是不需要编译的。

 1 #define PI
 2 using System;
 3 namespace PreprocessorDAppl
 4 {
 5    class Program
 6    {
 7       static void Main(string[] args)
 8       {
 9          #if (PI)
10             Console.WriteLine("PI is defined");     //PI不存在,则这条语句不编译
11          #else
12             Console.WriteLine("PI is not defined"); //PI存在,则这条语句不编译
13          #endif
14          Console.ReadKey();
15       }
16    }
17 }
View Code

  

  其他预处理器指令:

  1、#warning 和 #error:

    当编译器遇到它们时,会分别产生警告或错误。如果编译器遇到 #warning 指令,会给用户显示 #warning 指令后面的文本,之后编译继续进行。如果编译器遇到 #error 指令,就会给用户显示后面的文本,作为一条编译错误消息,然后会立即退出编译。使用这两条指令可以检查 #define 语句是不是做错了什么事,使用 #warning 语句可以提醒自己执行某个操作。

    #if DEBUG && RELEASE  
    #error "You've defined DEBUG and RELEASE simultaneously!"  
    #endif  
    #warning "Don't forget to remove this line before the boss tests the code!"  
    Console.WriteLine("*I hate this job.*");

  2. #region 和 #endregion

    #region 和 #endregion 指令用于把一段代码标记为有给定名称的一个块,如下所示:

    #region Member Field Declarations
    int x;
    double d;
    Currency balance;
    #endregion

    这看起来似乎没有什么用,它不影响编译过程。这些指令的优点是它们可以被某些编辑器识别,包括 Visual Studio .NET 编辑器。这些编辑器可以使用这些指令使代码在屏幕上更好地布局。

  3. #line

    #line 指令可以用于改变编译器在警告和错误信息中显示的文件名和行号信息,不常用。

    如果编写代码时,在把代码发送给编译器前,要使用某些软件包改变输入的代码,就可以使用这个指令,因为这意味着编译器报告的行号或文件名与文件中的行号或编辑的文件名不匹配。#line指令可以用于还原这种匹配。也可以使用语法#line default把行号还原为默认的行号:

    #line 164 "Core.cs" // 在文件的第 164 行
    // Core.cs, before the intermediate
    // package mangles it.
    // later on
    #line default // 恢复默认行号

  4. #pragma

    #pragma 指令可以抑制或还原指定的编译警告。与命令行选项不同,#pragma 指令可以在类或方法级别执行,对抑制警告的内容和抑制的时间进行更精细的控制。

    #pragma warning disable 169    // 取消编号 169 的警告(字段未使用的警告)
    public class MyClass
    {
        int neverUsedField;       // 编译整个 MyClass 类时不会发出警告
    }
    #pragma warning restore 169   // 恢复编号 169 的警告

五、正则表达式

  正则表达式 是一种匹配输入文本的模式。.Net 框架提供了允许这种匹配的正则表达式引擎。模式由一个或多个字符、运算符和结构组成。
    下面列出了用于定义正则表达式的各种类别的字符、运算符和结构:
      1、字符转义 2、字符类  3、定位点  4、分组构造  5、限定符  6、反向引用构造  7、备用构造  8、替换  9、杂项构造

  Regex 类:

    Regex 类用于表示一个正则表达式。下表列出了 Regex 类中一些常用的方法:

 

序号方法 & 描述
1 public bool IsMatch( string input ) 
指示 Regex 构造函数中指定的正则表达式是否在指定的输入字符串中找到匹配项。
2 public bool IsMatch( string input, int startat ) 
指示 Regex 构造函数中指定的正则表达式是否在指定的输入字符串中找到匹配项,从字符串中指定的开始位置开始。
3 public static bool IsMatch( string input, string pattern ) 
指示指定的正则表达式是否在指定的输入字符串中找到匹配项。
4 public MatchCollection Matches( string input ) 
在指定的输入字符串中搜索正则表达式的所有匹配项。
5 public string Replace( string input, string replacement ) 
在指定的输入字符串中,把所有匹配正则表达式模式的所有匹配的字符串替换为指定的替换字符串。
6 public string[] Split( string input ) 
把输入字符串分割为子字符串数组,根据在 Regex 构造函数中指定的正则表达式模式定义的位置进行分割。
  示例:

    1.验证电话号码:("^(\d{3.4}-)\d{7,8}$")正确格式:xxx/xxxx-xxxxxxx/xxxxxxxx;

    2.验证身份证号(15位或18位数字):("^\d{15}|\d{18}$");

    3.验证Email地址:("^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$");

    可参考:https://www.cnblogs.com/hehehehehe/p/6043710.html

六、异常处理

    异常是在程序执行期间出现的问题。C# 中的异常是对程序运行时出现的特殊情况的一种响应,比如尝试除以零。

    异常提供了一种把程序控制权从某个部分转移到另一个部分的方式。C# 异常处理时建立在四个关键词之上的:trycatchfinally 和 throw

      • try:一个 try 块标识了一个将被激活的特定的异常的代码块。后跟一个或多个 catch 块。
      • catch:程序通过异常处理程序捕获异常。catch 关键字表示异常的捕获。
      • finally:finally 块用于执行给定的语句,不管异常是否被抛出都会执行。例如,如果您打开一个文件,不管是否出现异常文件都要被关闭。
      • throw:当问题出现时,程序抛出一个异常。使用 throw 关键字来完成。
  1、异常类

      C# 异常是使用类来表示的。C# 中的异常类主要是直接或间接地派生于 System.Exception 类。System.ApplicationException 和 System.SystemException 类是派生于 System.Exception 类的异常类。

      System.ApplicationException 类支持由应用程序生成的异常。所以程序员定义的异常都应派生自该类。

      System.SystemException 类是所有预定义的系统异常的基类。


异常类描述
System.IO.IOException 处理 I/O 错误。
System.IndexOutOfRangeException 处理当方法指向超出范围的数组索引时生成的错误。
System.ArrayTypeMismatchException 处理当数组类型不匹配时生成的错误。
System.NullReferenceException 处理当依从一个空对象时生成的错误。
System.DivideByZeroException 处理当除以零时生成的错误。
System.InvalidCastException 处理在类型转换期间生成的错误。
System.OutOfMemoryException 处理空闲内存不足生成的错误。
System.StackOverflowException 处理栈溢出生成的错误。

  2、异常处理

      C# 以 try 和 catch 块的形式提供了一种结构化的异常处理方案。使用这些块,把核心程序语句与错误处理语句分离开。

      这些错误处理块是使用 trycatch 和 finally 关键字实现的。

      代码示例:
 1 using System;
 2 namespace ErrorHandlingApplication
 3 {
 4     class DivNumbers
 5     {
 6         int result;
 7         DivNumbers()
 8         {
 9             result = 0;
10         }
11         public void division(int num1, int num2)
12         {
13             try
14             {
15                 result = num1 / num2;
16             }
17             catch (DivideByZeroException e)
18             {
19                 Console.WriteLine("Exception caught: {0}", e);
20             }
21             finally
22             {
23                 Console.WriteLine("Result: {0}", result);
24             }
25 
26         }
27         static void Main(string[] args)
28         {
29             DivNumbers d = new DivNumbers();
30             d.division(25, 0);
31             Console.ReadKey();
32         }
33     }
34 }
35 //当上面的代码被编译和执行时,它会产生下列结果:
36 //Exception caught: System.DivideByZeroException: Attempted to //divide by zero. 
37 //at ...
38 //Result: 0
View Code

   3、自定义异常

    您也可以定义自己的异常。用户自定义的异常类是派生自 ApplicationException 类。

    代码示例:

 1 using System;
 2 namespace UserDefinedException
 3 {
 4    class TestTemperature
 5    {
 6       static void Main(string[] args)
 7       {
 8          Temperature temp = new Temperature();
 9          try
10          {
11             temp.showTemp();
12          }
13          catch(TempIsZeroException e)
14          {
15             Console.WriteLine("TempIsZeroException: {0}", e.Message);
16          }
17          Console.ReadKey();
18       }
19    }
20 }
21 public class TempIsZeroException: ApplicationException
22 {
23    public TempIsZeroException(string message): base(message)
24    {
25    }
26 }
27 public class Temperature
28 {
29    int temperature = 0;
30    public void showTemp()
31    {
32       if(temperature == 0)
33       {
34          throw (new TempIsZeroException("Zero Temperature found"));
35       }
36       else
37       {
38          Console.WriteLine("Temperature: {0}", temperature);
39       }
40    }
41 }
42 //执行结果
43 //TempIsZeroException: Zero Temperature found
View Code

   4、抛出对象

    如果异常是直接或间接派生自 System.Exception 类,您可以抛出一个对象。您可以在 catch 块中使用 throw 语句来抛出当前的对象,如下所示:

      Catch(Exception e)
      {
         ...
         Throw e
      }
七、文件的输入输出

    一个 文件 是一个存储在磁盘中带有指定名称和目录路径的数据集合。当打开文件进行读写时,它变成一个 

    从根本上说,流是通过通信路径传递的字节序列。有两个主要的流:输入流 和 输出流输入流用于从文件读取数据(读操作),输出流用于向文件写入数据(写操作)。

    1、I/O类

      System.IO 命名空间有各种不同的类,用于执行各种文件操作,如创建和删除文件、读取或写入文件,关闭文件等。

      下表列出了一些 System.IO 命名空间中常用的非抽象类:


I/O 类描述
BinaryReader 从二进制流读取原始数据。
BinaryWriter 以二进制格式写入原始数据。
BufferedStream 字节流的临时存储。
Directory 有助于操作目录结构。
DirectoryInfo 用于对目录执行操作。
DriveInfo 提供驱动器的信息。
File 有助于处理文件。
FileInfo 用于对文件执行操作。
FileStream 用于文件中任何位置的读写。
MemoryStream 用于随机访问存储在内存中的数据流。
Path 对路径信息执行操作。
StreamReader 用于从字节流中读取字符。
StreamWriter 用于向一个流中写入字符。
StringReader 用于读取字符串缓冲区。
StringWriter 用于写入字符串缓冲区。
    2、FileStream 类
     
 System.IO 命名空间中的 FileStream 类有助于文件的读写与关闭。该类派生自抽象类 Stream。
参数描述
FileMode

FileMode 枚举定义了各种打开文件的方法。FileMode 枚举的成员有:

  • Append:打开一个已有的文件,并将光标放置在文件的末尾。如果文件不存在,则创建文件。
  • Create:创建一个新的文件。如果文件已存在,则删除旧文件,然后创建新文件。
  • CreateNew:指定操作系统应创建一个新的文件。如果文件已存在,则抛出异常。
  • Open:打开一个已有的文件。如果文件不存在,则抛出异常。
  • OpenOrCreate:指定操作系统应打开一个已有的文件。如果文件不存在,则用指定的名称创建一个新的文件打开。
  • Truncate:打开一个已有的文件,文件一旦打开,就将被截断为零字节大小。然后我们可以向文件写入全新的数据,但是保留文件的初始创建日期。如果文件不存在,则抛出异常。
FileAccess

FileAccess 枚举的成员有:ReadReadWrite 和 Write

FileShare

FileShare 枚举的成员有:

  • Inheritable:允许文件句柄可由子进程继承。Win32 不直接支持此功能。
  • None:谢绝共享当前文件。文件关闭前,打开该文件的任何请求(由此进程或另一进程发出的请求)都将失败。
  • Read:允许随后打开文件读取。如果未指定此标志,则文件关闭前,任何打开该文件以进行读取的请求(由此进程或另一进程发出的请求)都将失败。但是,即使指定了此标志,仍可能需要附加权限才能够访问该文件。
  • ReadWrite:允许随后打开文件读取或写入。如果未指定此标志,则文件关闭前,任何打开该文件以进行读取或写入的请求(由此进程或另一进程发出)都将失败。但是,即使指定了此标志,仍可能需要附加权限才能够访问该文件。
  • Write:允许随后打开文件写入。如果未指定此标志,则文件关闭前,任何打开该文件以进行写入的请求(由此进程或另一进过程发出的请求)都将失败。但是,即使指定了此标志,仍可能需要附加权限才能够访问该文件。
  • Delete:允许随后删除文件。

    3、文件属性操作

      File类与FileInfo都能实现。静态方法与实例化方法的区别!

        //use File class
        Console.WriteLine(File.GetAttributes(filePath));
        File.SetAttributes(filePath,FileAttributes.Hidden | FileAttributes.ReadOnly);
        Console.WriteLine(File.GetAttributes(filePath));

        //user FilInfo class
        FileInfo fi = new FileInfo(filePath);
        Console.WriteLine(fi.Attributes.ToString());
        fi.Attributes = FileAttributes.Hidden | FileAttributes.ReadOnly; //隐藏与只读
        Console.WriteLine(fi.Attributes.ToString());

        //只读与系统属性,删除时会提示拒绝访问
        fi.Attributes = FileAttributes.Archive;
        Console.WriteLine(fi.Attributes.ToString());
     4、文件路径操作

        文件和文件夹的路径操作都在Path类中。另外还可以用Environment类,里面包含环境和程序的信息。
string dirPath = @"D:\TestDir";
string filePath = @"D:\TestDir\TestFile.txt";
Console.WriteLine("<<<<<<<<<<<{0}>>>>>>>>>>", "文件路径");
//获得当前路径
Console.WriteLine(Environment.CurrentDirectory);
//文件或文件夹所在目录
Console.WriteLine(Path.GetDirectoryName(filePath));     //D:\TestDir
Console.WriteLine(Path.GetDirectoryName(dirPath));      //D:\
//文件扩展名
Console.WriteLine(Path.GetExtension(filePath));         //.txt
//文件名
Console.WriteLine(Path.GetFileName(filePath));          //TestFile.txt
Console.WriteLine(Path.GetFileName(dirPath));           //TestDir
Console.WriteLine(Path.GetFileNameWithoutExtension(filePath)); //TestFile
//绝对路径
Console.WriteLine(Path.GetFullPath(filePath));          //D:\TestDir\TestFile.txt
Console.WriteLine(Path.GetFullPath(dirPath));           //D:\TestDir  
//更改扩展名
Console.WriteLine(Path.ChangeExtension(filePath, ".jpg"));//D:\TestDir\TestFile.jpg
//根目录
Console.WriteLine(Path.GetPathRoot(dirPath));           //D:\      
//生成路径
Console.WriteLine(Path.Combine(new string[] { @"D:\", "BaseDir", "SubDir", "TestFile.txt" })); //D:\BaseDir\SubDir\TestFile.txt
//生成随即文件夹名或文件名
Console.WriteLine(Path.GetRandomFileName());
//创建磁盘上唯一命名的零字节的临时文件并返回该文件的完整路径
Console.WriteLine(Path.GetTempFileName());
//返回当前系统的临时文件夹的路径
Console.WriteLine(Path.GetTempPath());
//文件名中无效字符
Console.WriteLine(Path.GetInvalidFileNameChars());
//路径中无效字符
Console.WriteLine(Path.GetInvalidPathChars()); 
View Code

    5、高级文件操作

      上面的实例演示了 C# 中简单的文件操作。但是,要充分利用 C# System.IO 类的强大功能,您需要知道这些类常用的属性和方法。

      在下面的章节中,我们将讨论这些类和它们执行的操作。请单击链接详细了解各个部分的知识:


主题描述
文本文件的读写 它涉及到文本文件的读写。StreamReader 和 StreamWriter 类有助于完成文本文件的读写。
二进制文件的读写 它涉及到二进制文件的读写。BinaryReader 和 BinaryWriter 类有助于完成二进制文件的读写。
Windows 文件系统的操作 它让 C# 程序员能够浏览并定位 Windows 文件和目录。

 

    参考文献:https://www.runoob.com/csharp/csharp-encapsulation.html

根据w3school自我温习一下c#基础,到这里c#基础就结束了,下步会自习一下c#的高级特性。