unity的C#学习——预处理指令、异常处理和文件的输入输出


预处理器指令

C# 中的预处理器指令是用来指示编译器在编译代码之前执行一些预处理操作的特殊指令。预处理器指令以井号 # 开始,并且必须出现在代码的最外层,不能包含在方法或类的内部。


1、#define

#define 指令用于定义一个符号常量。符号常量可以在代码中使用 #if#elif 指令进行条件编译。例如:

#define DEBUG
#if DEBUG
    Console.WriteLine("Debug mode is enabled.");
#endif

在上面的示例中,我们使用 #define 指令定义了一个名为 DEBUG 的符号常量。然后在 #if 指令中,根据 DEBUG 符号常量是否已定义(定义判定为true,未定义判定为false)来编译代码块。


2、#undef

#undef 指令用于取消已定义的符号常量。例如:

#define DEBUG
#if DEBUG
    Console.WriteLine("Debug mode is enabled.");
#endif

#undef DEBUG
#if DEBUG
    Console.WriteLine("Debug mode is still enabled.");
#endif

在上面的示例中,我们首先使用 #define 指令定义了一个名为 DEBUG 的符号常量。然后在 #if 指令中,根据 DEBUG 符号常量是否已定义来编译代码块。接着使用 #undef 指令取消了 DEBUG 符号常量的定义,再次使用 #if 指令来编译代码块。


3、#if, #elif, #else, #endif

  • #if 指令用于根据符号常量是否已定义来编译代码块。如果符号常量已定义,则编译代码块。

例如:

#define DEBUG
#if DEBUG
    Console.WriteLine("Debug mode is enabled.");
#endif
  • #elif 指令在 #if 指令中添加一个新的条件。如果之前的条件不成立,且当前条件成立,则编译代码块。
  • #else 指令在 #if#elif 指令中添加一个默认条件。如果之前的条件不成立,则编译代码块。
  • #endif 指令用于结束一个 #if#elif 块。

例如:

#define DEBUG
#if DEBUG
    Console.WriteLine("Debug mode is enabled.");
#elif RELEASE
    Console.WriteLine("Release mode is enabled.");
#else
    Console.WriteLine("Unknown mode is enabled.");
#endif

3.1 条件指令

我们可以使用 #if 指令来创建一个条件指令,该指令用于测试符号是否为真(即符号常量是否用#define定义)。如果为真,编译器会执行 #if 和下一个指令之间的代码。

条件指令的语法:

#if symbol [operator symbol]...
  • 其中symbol 是要测试的符号常量,我们也可以使用 truefalse,或在符号前放置否定运算符"!"
  • 常见运算符有:== (等于)!= (不等于)&& (与)|| (或)
  • 我们也可以用括号把符号和运算符进行分组。

条件指令用于在调试版本或编译指定配置时编译代码。一个以 #if 指令开始的条件指令,必须显示地以一个 #endif 指令终止。下面的程序演示了条件指令的用法:

#define DEBUG
#define VC_V10
using System;
public class TestClass
{
    
    
   public static void Main()
   {
    
    

      #if (DEBUG && !VC_V10)
         Console.WriteLine("DEBUG is defined");
      #elif (!DEBUG && VC_V10)
         Console.WriteLine("VC_V10 is defined");
      #elif (DEBUG && VC_V10)
         Console.WriteLine("DEBUG and VC_V10 are defined");
      #else
         Console.WriteLine("DEBUG and VC_V10 are not defined");
      #endif
      Console.ReadKey();
   }
}

当上面的代码被编译和执行时,它会产生下列结果:

DEBUG and VC_V10 are defined


4、#warning, #error

  • #warning 指令用于输出一个编译器警告。例如:
#if RELEASE
	#warning This code needs to be refactored.
  • #error 指令用于输出一个编译器错误。例如:
#if RELEASE
    #error This code needs to be refactored.

5、#region, #endregion

  • #region 指令用于将代码块分组,并可以为其命名。
  • #endregion 指令用于结束一个 #region 块。

例如:

#region MyRegion
    Console.WriteLine("This code is in MyRegion.");
#endregion

在 Visual Studio 编辑器中,可以使用加号展开或减号折叠一个 #region 块。


6、#pragma

#pragma 指令用于向编译器发送特定的指令。例如:

#pragma warning disable
    // some code
#pragma warning restore

在上面的示例中,#pragma warning disable 指令告诉编译器禁用所有警告,#pragma warning restore 指令告诉编译器恢复之前的警告设置。


7、#nullable

#nullable 指令用于为整个文件或特定作用域启用或禁用可空引用类型。例如:

#nullable enable
    string? name = null;
    Console.WriteLine(name.Length); // warning CS8602
#nullable disable
    string? name = null;
    Console.WriteLine(name.Length); // no warning

在上面的示例中,#nullable enable 指令启用可空引用类型检查,#nullable disable 指令禁用可空引用类型检查。


8、#pragma warning

#pragma warning 指令用于设置编译器警告的级别禁用/启用特定的警告。例如:

// 禁用编译器警告 CS0219(变量未使用)
#pragma warning disable CS0219
    int unused = 0;
// 恢复编译器警告 CS0219
#pragma warning restore CS0219

// 禁用编译器警告 CS8602(可能的空引用异常)
#pragma warning disable CS8602
    string? name = null;
    Console.WriteLine(name.Length); // 不会出现警告
// 恢复编译器警告 CS8602
#pragma warning restore CS8602

// 抑制编译器警告 CS8600(空引用检查可能不准确)
#pragma warning suppress CS8600
    string? name = null;
    Console.WriteLine(name.Length); // 警告 CS8602

在上面的示例中,#pragma warning disable 指令禁用特定警告,#pragma warning restore 指令恢复之前的警告设置,#pragma warning suppress 指令抑制特定警告。


异常处理

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

在C#中,异常处理是通过捕获并处理异常对象来处理运行时错误的过程。在执行程序时,如果发生异常,程序会停止执行,并且会生成一个异常对象。如果不对异常进行处理,程序将会崩溃。

C#提供了一组关键字和语法结构,用于捕获和处理异常。以下是一些常见的异常处理关键字和语法:


1、try-catch语句

try-catch语句用于捕获和处理异常。在try块中编写可能会抛出异常的代码,在catch块中编写处理异常的代码。如果try块中的代码引发异常,程序将会跳转到catch块中,执行相应的异常处理代码。

以下是try-catch语句的基本语法:

try
{
    
    
    // 可能会抛出异常的代码
}
catch (Exception ex)
{
    
    
    // 处理异常的代码
}

2、finally块

finally块用于编写无论是否发生异常都需要执行的代码。在finally块中编写的代码将在try块或catch块执行完毕后执行。

以下是finally块的基本语法:

try
{
    
    
    // 可能会抛出异常的代码
}
catch (Exception ex)
{
    
    
    // 处理异常的代码
}
finally
{
    
    
    // 无论是否发生异常都需要执行的代码
}
  • 如果在try-catch语句中添加了return语句,finally块会在return语句执行之前执行。

这是因为finally块中的代码是在try-catch块中的所有代码执行完成后执行的,而return语句会立即结束当前方法的执行并返回结果,因此finally块中的代码会在return语句执行之前被执行。以下是一个示例:

public int DoSomething()
{
    
    
    try
    {
    
    
        // 可能会抛出异常的代码
        return 1;
    }
    catch (Exception ex)
    {
    
    
        // 处理异常的代码
        return 0;
    }
    finally
    {
    
    
        // 无论是否发生异常都需要执行的代码
        Console.WriteLine("finally block executed.");
    }
}

在上面的示例中,如果try块中的代码没有抛出异常,将返回值1,并且finally块中的代码将被执行。如果try块中的代码抛出了异常,将返回值0,并且finally块中的代码也将被执行。无论是哪种情况,finally块中的代码都会在返回结果之前执行。


3、throw语句

throw语句用于在程序中抛出一个异常对象。当程序执行到throw语句时,程序将停止执行,并将控制权转移到最近的catch块

以下是throw语句的基本语法:

throw new Exception("错误消息");

4、内置的异常类

在C#中,异常类是用于处理程序中出现的错误情况的类。当程序运行时出现异常,会创建一个异常对象,其中包含有关异常情况的信息,例如异常类型、消息、堆栈跟踪和其他有用的调试信息。开发人员可以使用C#中的异常类来处理异常,以便使程序在出现异常时能够更加可靠地运行和恢复。

在C#中,常见的异常类包括:

序号 异常类名 描述
1 System.Exception 所有异常的基类。
2 System.ApplicationException 用户自定义异常类应该派生自此类。
3 System.ArgumentException 表示参数错误异常。
4 System.ArgumentNullException 表示参数为 null 的异常。
5 System.ArgumentOutOfRangeException 表示参数超出范围的异常。
6 System.ArrayTypeMismatchException 表示数组类型不匹配的异常。
7 System.DivideByZeroException 表示除数为零的异常。
8 System.IndexOutOfRangeException 表示索引超出范围的异常。
9 System.IO.IOException 表示输入输出错误的异常。
10 System.InvalidCastException 表示类型转换无效的异常。
11 System.NullReferenceException 表示对象为 null 的异常。
12 System.OutOfMemoryException 表示内存不足的异常。
13 System.StackOverflowException 表示堆栈溢出的异常。

这些异常类提供了许多属性和方法,以便开发人员能够识别、记录和处理异常。

  • 开发人员可以在catch语句内指定需要捕获和处理异常类;
  • 还可以使用throw语句在代码中显式地引发异常。

以下是一个示例:

using System

try
{
    
    
    // 可能会抛出异常的代码
}
catch (ArgumentNullException ex)
{
    
    
    // 处理参数为null的异常,可以通过对象ex输出异常类型
}
catch (Exception ex)
{
    
    
    // 处理其他类型的异常,可以通过对象ex输出异常类型
}
finally
{
    
    
    // 无论是否发生异常都需要执行的代码
}

在上面的示例中,try块中的代码可能会抛出异常。如果抛出的异常类型是ArgumentNullException,则会执行第一个catch块中的代码;如果是其他类型的异常,则会执行第二个catch块中的代码。无论是否发生异常,finally块中的代码都将被执行。


5、自定义异常类

在C#中,可以定义自己的异常类,以便更好地描述程序中发生的错误。用户自定义异常类可以派生自System.Exception类,也可以派生自ApplicationException类,它们都提供了一些方法和属性,用于处理和描述异常。

  • ApplicationException 类是 System.Exception 类的一个子类,它在 .NET Framework 1.1中引入,旨在提供一种更好的异常处理方法。
  • 不过随着 .NET Framework 2.0的发布,微软官方建议开发者不再使用ApplicationException类来派生自定义异常类,而是直接从 System.Exception 派生。这是因为在 .NET Framework 2.0及以后的版本中,ApplicationException 类没有提供额外的功能,与 System.Exception 类没有什么区别。

在使用自定义异常类时,可以使用throw语句抛出自定义异常对象。以下是自定义异常类的基本语法:

using System

// 自定义异常类,继承基类Exception
public class MyException : Exception
{
    
    
    public MyException(string message) : base(message)
    {
    
    
    	throw new MyException("错误消息");
    }
}

文件的输入输出

一个文件是一个存储在磁盘中带有指定名称和目录路径的数据集合。当打开文件进行读写时,它变成一个 流。从根本上说,流是通过通信路径传递的字节序列。有两个主要的流:

  • 输入流:用于从文件读取数据(读操作)。
  • 输出流:用于向文件写入数据(写操作)。

1、I/O 相关类列举

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

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

序号 I/O 类 描述
1 BinaryReader 从二进制流读取原始数据。
2 BinaryWriter 以二进制格式写入原始数据。
3 BufferedStream 字节流的临时存储。
4 Directory 有助于操作目录结构。
5 DirectoryInfo 用于对目录执行操作。
6 DriveInfo 提供驱动器的信息。
7 File 有助于处理文件。
8 FileInfo 用于对文件执行操作。
9 FileStream 用于文件中任何位置的读写。
10 MemoryStream 用于随机访问存储在内存中的数据流。
11 Path 对路径信息执行操作。
12 StreamReader 用于从字节流中读取字符。
13 StreamWriter 用于向一个流中写入字符。
14 StringReader 用于读取字符串缓冲区。
15 StringWriter 用于写入字符串缓冲区。

2、FileStream 类

System.IO 命名空间中的 FileStream 类有助于文件的读写与关闭。该类派生自抽象类 Stream

我们需要通过创建一个 FileStream 对象来创建一个新的文件,或打开一个已有的文件。创建 FileStream 对象的语法如下:

FileStream <object_name> = new FileStream( <file_name>, <FileMode Enumerator>, <FileAccess Enumerator>, <FileShare Enumerator>);
参数 描述
FileMode FileMode 枚举类型定义了打开文件的不同方式。FileMode 枚举的成员有:

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

Read:表示以只读方式打开文件,不允许写入文件。
Write:表示以只写方式打开文件,不允许读取文件。
ReadWrite:表示以读写方式打开文件,既可以读取也可以写入文件。
FileShare FileShare 枚举类型定义了文件的共享模式,FileShare 枚举的成员有:

Inheritable:允许文件句柄可由子进程继承。Win32 不直接支持此功能。
None:不允许其他进程访问该文件。文件关闭前,打开该文件的任何请求(由此进程或另一进程发出的请求)都将失败。
Read:允许其他进程以只读方式访问该文件。如果未指定此标志,则文件关闭前,任何打开该文件以进行读取的请求(由此进程或另一进程发出的请求)都将失败。但是,即使指定了此标志,仍可能需要附加权限才能够访问该文件。
ReadWrite:允许其他进程以读写方式访问该文件。如果未指定此标志,则文件关闭前,任何打开该文件以进行读取或写入的请求(由此进程或另一进程发出)都将失败。但是,即使指定了此标志,仍可能需要附加权限才能够访问该文件。
Write:允许其他进程以只写方式访问该文件。如果未指定此标志,则文件关闭前,任何打开该文件以进行写入的请求(由此进程或另一进过程发出的请求)都将失败。但是,即使指定了此标志,仍可能需要附加权限才能够访问该文件。
Delete:允许其他进程删除该文件。这意味着如果一个进程以此参数打开了一个文件,它可以在文件关闭前删除该文件。如果其他进程正在写入该文件,则会出现冲突。

例如,创建一个 FileStream 对象 F 来读取名为 sample.txt 的文件:

FileStream F = new FileStream("sample.txt", FileMode.Open, FileAccess.Read, FileShare.Read);
  • File.OpenSystem.IO命名空间中的静态方法,可以用于打开一个文件并返回一个FileStream对象,它提供了对文件的基本操作。

使用File.Open方法时,需要指定文件名、打开方式、访问权限等参数,如上例也可写成:

FileStream F = File.Open("sample.txt", FileMode.Open, FileAccess.Read, FileShare.Read);

下面的程序详细演示了 FileStream 类的用法:

using System;
using System.IO;

namespace FileIOApplication
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            // 创建一个FileStream对象来打开一个文件test.dat,以进行读写操作
            // 如果文件不存在,则创建新文件;如果文件已经存在,则打开文件进行读写
            FileStream F = new FileStream("test.dat", FileMode.OpenOrCreate, FileAccess.ReadWrite);

            // 写入20个字节到文件中
            for (int i = 1; i <= 20; i++)
            {
    
    
                F.WriteByte((byte)i);
            }

            // 重置流的位置到文件开头
            F.Position = 0;

            // 读取文件中的每个字节,并打印到控制台
            for (int i = 0; i <= 20; i++)
            {
    
    
                Console.Write(F.ReadByte() + " ");
            }

            // 关闭文件流
            F.Close();

            // 等待用户按下一个键继续
            Console.ReadKey();
        }
    }
}

当上面的代码被编译和执行时,它会产生下列结果:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 -1


2、StreamReader 和 StreamWriter 类

在C#中,StreamReader 类和 StreamWriter 类都是用于读取和写入文本文件的类。

  • StreamReader类用于从文本文件中读取字符,是以文本为单位进行读取操作的。它可以读取文件中的字符串、字符和行等数据。当读取的字符集不是Unicode时,可以使用编码来转换字符集。

下表列出了 StreamReader 类中一些常用的方法

序号 方法 描述
1 public override void Close() 关闭 StreamReader 对象和基础流,并释放任何与读者相关的系统资源。
2 public override int Peek() 返回下一个可用的字符,但不使用它。
3 public override int Read() 从输入流中读取下一个字符,并把字符位置往前移一个字符。

示例代码:

using System;
using System.IO;

namespace FileIOApplication
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            // 指定读取的文件路径
            string filePath = "example.txt";
            
            // 创建一个 StreamReader 对象,以 UTF-8 编码方式打开指定文件
            StreamReader reader = new StreamReader(filePath);

            // 循环读取文件中的每一行直到文件末尾
            while (!reader.EndOfStream)
            {
    
    
                // 读取文件中的一行,并将其存储到 line 变量中
                string line = reader.ReadLine();
                
                // 在控制台中输出当前行
                Console.WriteLine(line);
            }

            // 关闭 StreamReader 对象
            reader.Close();
            
            // 等待用户按下任意键结束程序
            Console.ReadKey();
        }
    }
}
  • StreamWriter类用于向文本文件中写入字符,是以文本为单位进行写入操作的。它可以写入字符串、字符和行等数据。当写入的字符集不是Unicode时,可以使用编码来转换字符集。

下表列出了 StreamWriter 类中一些常用的方法

序号 方法 描述
1 public override void Close() 关闭当前的 StreamWriter 对象和基础流。
2 public override void Flush() 清理当前编写器的所有缓冲区,使得所有缓冲数据写入基础流。
3 public virtual void Write(bool value) 把一个布尔值的文本表示形式写入到文本字符串或流。(继承自 TextWriter。)
4 public override void Write( char value ) 把一个字符写入到流。
5 public virtual void Write( decimal value ) 把一个十进制值的文本表示形式写入到文本字符串或流。
6 public virtual void Write( double value ) 把一个 8 字节浮点值的文本表示形式写入到文本字符串或流。
7 public virtual void Write( int value ) 把一个 4 字节有符号整数的文本表示形式写入到文本字符串或流。
8 public override void Write( string value ) 把一个字符串写入到流。
9 public virtual void WriteLine() 把行结束符写入到文本字符串或流。

示例代码:

using System;
using System.IO;

namespace FileIOApplication
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            string filePath = "example.txt";
            // 创建一个 StreamWriter 对象并传入文件路径,如果文件不存在则创建,如果存在则覆盖
            StreamWriter writer = new StreamWriter(filePath);

            // 向文件中写入两行文本
            writer.WriteLine("Hello World!");
            writer.WriteLine("Welcome to C# programming!");

            // 关闭 StreamWriter 对象
            writer.Close();
            Console.ReadKey();
        }
    }
}

在使用StreamReaderStreamWriter类时,需要注意关闭流,以释放相关资源,避免内存泄漏。可以使用Close方法或使用using语句块来自动关闭流。


3、BinaryReader 和 BinaryWriter 类

在C#中,BinaryReaderBinaryWriter 类是是用于读取和写入二进制文件的类。

  • BinaryReader 类用于从文件读取二进制数据。一个 BinaryReader 对象通过向它的构造函数传递 FileStream 对象而被创建。下表列出了 BinaryReader 类中一些常用的方法:
序号 方法 描述
1 public override void Close() 关闭 BinaryReader 对象和基础流。
2 public virtual int Read() 从基础流中读取字符,并把流的当前位置往前移。
3 public virtual bool ReadBoolean() 从当前流中读取一个布尔值,并把流的当前位置往前移一个字节。
4 public virtual byte ReadByte() 从当前流中读取下一个字节,并把流的当前位置往前移一个字节。
5 public virtual byte[] ReadBytes(int count) 从当前流中读取指定数目的字节到一个字节数组中,并把流的当前位置往前移指定数目的字节。
6 public virtual char ReadChar() 从当前流中读取下一个字节,并把流的当前位置按照所使用的编码和从流中读取的指定的字符往前移。
7 public virtual char[] ReadChars(int count) 从当前流中读取指定数目的字节,在一个字符数组中返回数组,并把流的当前位置按照所使用的编码和从流中读取的指定的字符往前移。
8 public virtual double ReadDouble() 从当前流中读取一个 8 字节浮点值,并把流的当前位置往前移八个字节。
9 public virtual int ReadInt32() 从当前流中读取一个 4 字节有符号整数,并把流的当前位置往前移四个字节。
10 public virtual string ReadString() 从当前流中读取一个字符串。字符串以长度作为前缀,同时编码为一个七位的整数。
  • BinaryWriter 类用于向文件写入二进制数据。一个 BinaryWriter 对象通过向它的构造函数传递 FileStream 对象而被创建。下表列出了 BinaryWriter 类中一些常用的方法:
序号 方法 描述
1 public override void Close() 关闭 BinaryWriter 对象和基础流。
2 public virtual void Flush() 清理当前编写器的所有缓冲区,使得所有缓冲数据写入基础设备。
3 public virtual long Seek( int offset, SeekOrigin origin ) 设置当前流内的位置。
4 public virtual void Write( bool value ) 把一个单字节的布尔值写入到当前流中,0 表示 false,1 表示 true。
5 public virtual void Write( byte value ) 把一个无符号字节写入到当前流中,并把流的位置往前移一个字节。
6 public virtual void Write( byte[] buffer ) 把一个字节数组写入到基础流中。
7 public virtual void Write( char ch ) 把一个 Unicode 字符写入到当前流中,并把流的当前位置按照所使用的编码和要写入到流中的指定的字符往前移。
8 public virtual void Write( char[] chars ) 把一个字符数组写入到当前流中,并把流的当前位置按照所使用的编码和要写入到流中的指定的字符往前移。
9 public virtual void Write( double value ) 把一个 8 字节浮点值写入到当前流中,并把流位置往前移八个字节。
10 public virtual void Write( int value ) 把一个 4 字节有符号整数写入到当前流中,并把流位置往前移四个字节。
11 public virtual void Write( string value ) 把一个以长度为前缀的字符串写入到 BinaryWriter 的当前编码的流中,并把流的当前位置按照所使用的编码和要写入到流中的指定的字符往前移。

其中序号4-11的方法属于之前提到的函数重载,通过不同的参数类型实现。

下面的实例演示了读取和写入二进制数据:

using System;
using System.IO;

namespace BinaryFileApplication
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            BinaryWriter bw; // 声明 BinaryWriter 对象
            BinaryReader br; // 声明 BinaryReader 对象
            int i = 25; // 定义一个 int 类型的变量 i
            double d = 3.14157; // 定义一个 double 类型的变量 d
            bool b = true; // 定义一个 bool 类型的变量 b
            string s = "I am happy"; // 定义一个 string 类型的变量 s

            // 创建文件
            try
            {
    
    
                bw = new BinaryWriter(new FileStream("mydata", FileMode.Create)); // 创建名为 mydata 的二进制文件
            }
            catch (IOException e)
            {
    
    
                Console.WriteLine(e.Message + "\n Cannot create file."); // 文件创建失败时输出错误信息
                return;
            }

            // 写入文件
            try
            {
    
    
                bw.Write(i); // 将变量 i 写入文件
                bw.Write(d); // 将变量 d 写入文件
                bw.Write(b); // 将变量 b 写入文件
                bw.Write(s); // 将变量 s 写入文件
            }
            catch (IOException e)
            {
    
    
                Console.WriteLine(e.Message + "\n Cannot write to file.");  // 写入文件失败时输出错误信息
                return;
            }

            bw.Close();  // 关闭 BinaryWriter 对象

            // 读取文件
            try
            {
    
    
                br = new BinaryReader(new FileStream("mydata", FileMode.Open)); // 打开名为 mydata 的二进制文件
            }
            catch (IOException e)
            {
    
    
                Console.WriteLine(e.Message + "\n Cannot open file."); 	// 文件打开失败时输出错误信息
                return;
            }

            try
            {
    
    
                i = br.ReadInt32(); 		// 读取 int 类型的数据并存储到变量 i 中
                Console.WriteLine("Integer data: {0}", i); 	// 输出变量 i 的值
                d = br.ReadDouble(); 		// 读取 double 类型的数据并存储到变量 d 中
                Console.WriteLine("Double data: {0}", d); 	// 输出变量 d 的值
                b = br.ReadBoolean(); 		// 读取 bool 类型的数据并存储到变量 b 中
                Console.WriteLine("Boolean data: {0}", b);	// 输出变量 b 的值
                s = br.ReadString(); 		// 读取 string 类型的数据并存储到变量 s 中
                Console.WriteLine("String data: {0}", s); 	// 输出变量 s 的值
            }
            catch (IOException e)
            {
    
    
                Console.WriteLine(e.Message + "\n Cannot read from file."); // 从文件读取数据失败时输出错误信息
                return;
            }

            br.Close(); // 关闭 BinaryReader 对象

            Console.ReadKey(); // 等待用户按下任意键继续执行程序
        }
    }
}

当上面的代码被编译和执行时,它会产生下列结果:

Integer data: 25
Double data: 3.14157
Boolean data: True
String data: I am happy


4、DirectoryInfo 类

DirectoryInfo 类派生自 FileSystemInfo 类。它提供了各种用于创建、移动、浏览目录和子目录的方法。该类不能被继承。

DirectoryInfo的实例化语法如下:

DirectoryInfo dir = new DirectoryInfo("path");
  • 其中 path 是一个字符串,指定了目录的路径,可以使用绝对路径或相对路径

下表列出了 DirectoryInfo 类中一些常用的属性

序号 属性 描述
1 Attributes 获取当前文件或目录的属性。
2 CreationTime 获取当前文件或目录的创建时间。
3 Exists 获取一个表示目录是否存在的布尔值。
4 Extension 获取表示文件存在的字符串。
5 FullName 获取目录或文件的完整路径。
6 LastAccessTime 获取当前文件或目录最后被访问的时间。
7 Name 获取该 DirectoryInfo 实例的名称。

下表列出了 DirectoryInfo 类中一些常用的方法

序号 方法 描述
1 public void Create() 创建一个目录。
2 public DirectoryInfo CreateSubdirectory(string path) 在指定的路径上创建子目录。指定的路径可以是相对于 DirectoryInfo 类的实例的路径。
3 public override void Delete() 如果为空的,则删除该 DirectoryInfo。
4 public DirectoryInfo[] GetDirectories() 返回当前目录的子目录。
5 public FileInfo[] GetFiles() 从当前目录返回文件列表。

以下是使用 DirectoryInfo 类的示例代码,包括实例化 DirectoryInfo 对象、获取目录信息、创建目录和删除目录:

using System;
using System.IO;

class Program
{
    
    
    static void Main(string[] args)
    {
    
    
        // 实例化 DirectoryInfo 对象
        DirectoryInfo directory = new DirectoryInfo(@"C:\temp");

        // 获取目录(属性)信息
        Console.WriteLine($"Directory Name: {
      
      directory.Name}");
        Console.WriteLine($"Full Directory Name: {
      
      directory.FullName}");
        Console.WriteLine($"Parent Directory: {
      
      directory.Parent}");
        Console.WriteLine($"Creation Time: {
      
      directory.CreationTime}");
        Console.WriteLine($"Last Access Time: {
      
      directory.LastAccessTime}");
        Console.WriteLine($"Last Write Time: {
      
      directory.LastWriteTime}");

        // 创建目录
        if (!directory.Exists)
        {
    
    
            directory.Create();
            Console.WriteLine("Directory created successfully.");
        }
        else
        {
    
    
            Console.WriteLine("Directory already exists.");
        }

        // 删除目录
        directory.Delete();
        Console.WriteLine("Directory deleted successfully.");

        Console.ReadKey();
    }
}

5、FileInfo 类

FileInfo 类派生自 FileSystemInfo 类。它提供了用于创建、复制、删除、移动、打开文件的属性和方法,且有助于 FileStream 对象(用于文件读写)的创建。该类不能被继承。

  • 实例化 FileInfo 类时,同样需要指定文件路径作为构造函数的参数,例如:
FileInfo fileInfo = new FileInfo("path/to/file.txt");

下表列出了 FileInfo 类中一些常用的属性

序号 属性 描述
1 Attributes 获取当前文件的属性。
2 CreationTime 获取当前文件的创建时间。
3 Directory 获取文件所属目录的一个实例。
4 Exists 获取一个表示文件是否存在的布尔值。
5 Extension 获取表示文件存在的字符串。
6 FullName 获取文件的完整路径。
7 LastAccessTime 获取当前文件最后被访问的时间。
8 LastWriteTime 获取文件最后被写入的时间。
9 Length 获取当前文件的大小,以字节为单位。
10 Name 获取文件的名称。

下表列出了 FileInfo 类中一些常用的方法

序号 方法 描述
1 public StreamWriter AppendText() 创建一个 StreamWriter,追加文本到由 FileInfo 的实例表示的文件中。
2 public FileStream Create() 创建一个文件。
3 public override void Delete() 永久删除一个文件。
4 public void MoveTo( string destFileName ) 移动一个指定的文件到一个新的位置,提供选项来指定新的文件名。
5 public FileStream Open( FileMode mode ) 以指定的模式打开一个文件。
6 public FileStream Open( FileMode mode, FileAccess access ) 以指定的模式,使用 read、write 或 read/write 访问,来打开一个文件。
7 public FileStream Open( FileMode mode, FileAccess access, FileShare share ) 以指定的模式,使用 read、write 或 read/write 访问,以及指定的分享选项,来打开一个文件。
8 public FileStream OpenRead() 创建一个只读的 FileStream。
9 public FileStream OpenWrite() 创建一个只写的 FileStream。

以下是使用 FileInfo 类的示例代码:

using System;
using System.IO;

class Program
{
    
    
    static void Main(string[] args)
    {
    
    
        // 创建 FileInfo 实例
        FileInfo file = new FileInfo("test.txt");

        // 检查文件是否存在
        if (file.Exists)
        {
    
    
            Console.WriteLine("文件已存在。");

            // 获取文件的创建时间和修改时间
            Console.WriteLine("文件创建时间:" + file.CreationTime);
            Console.WriteLine("文件修改时间:" + file.LastWriteTime);

            // 获取文件大小(以字节为单位)
            Console.WriteLine("文件大小:" + file.Length + " 字节");

            // 获取文件名和文件路径
            Console.WriteLine("文件名:" + file.Name);
            Console.WriteLine("文件路径:" + file.FullName);

            // 重命名文件
            FileInfo newFile = new FileInfo("newTest.txt");
            file.MoveTo(newFile.FullName);
            Console.WriteLine("文件已重命名为:" + newFile.Name);

            // 删除文件
            newFile.Delete();
            Console.WriteLine("文件已删除。");
        }
        else
        {
    
    
            // 创建文件
            using (StreamWriter sw = file.CreateText())
            {
    
    
                sw.WriteLine("这是一个测试文件。");
            }

            Console.WriteLine("文件已创建。");
        }

        Console.ReadKey();
    }
}

猜你喜欢

转载自blog.csdn.net/qq_50571974/article/details/129778719