C#学习之旅(六)

C#学习之旅(六)

1、泛型

        泛型是C#和公共语言运行库(CLR)中的一个功能,泛型的概念在Java语言的较新版本中也已经被支持,这是一种可以使程序支持不同类型的技术。它将类型参数的概念引入.NET Framework中,类型参数将一个或多个类型的指定推迟到客户端代码声明并实例化该类或方法。

        1.1、泛型的概述

        泛型是用于处理算法、数据结构的一种编程方法。泛型的目标是采用广泛适用和可交互性的形式来表示算法和数据结构,以使它们能够直接用于软件构造。泛型类、结构、接口、委托和方法可以根据它们存储和操作的数据的类型来进行参数化。泛型能在编译时提供强大的类型检查,减少数据类型之间的显示转换、装箱操作和运行时的类型检查。泛型类和泛型方法同时具备可重用性、类型安全和效率高等特性,这是非泛型类和非泛型方法无法具备的。泛型通常用在集合和在集合上运行的方法中。
    泛型主要是提高了代码的重用性,比如,可以将泛型看成是一个可以回收的包装箱A。如果在包装箱A上贴上苹果标签,就可以在包装箱A里装上苹果进行发送;如果在包装箱A上贴上香蕉标签,就可以在包装箱A里装上香蕉进行发送。

        1.2、泛型的使用

        1.2.1、类型参数 T

        泛型的类型参数T可以看作是一个占位符,它不是一种类型,它仅代表了某种可能的类型。在定义泛型时T出现的位置可以在使用任何类型来代替。类型参数T的命名准则如下:
    <1>、使用描述性名称命名泛型类型参数,除非单个字母名称完全可以让人了解它表示的含义,而描述性名称不会有更多的意义。
    例如:
    public interface ISessionChannel<Session>
    public delegate TOutput Converter<Input, Output>

    <2>、将T作为描述性类型参数名的前缀。
    例如:
    public interface ISessionChannel<T>
    {
        T Session { get; }
    }

        1.2.2、泛型接口

        泛型接口的声明形式如下。
    interface 【接口名】<T>
    {
        【接口体】
    }
    声明泛型接口时,与声明一般接口的唯一区别是增加了一个<T>。一般来说,声明泛型接口与声明非泛型接口遵循相同的规则。泛型类型声明所实现的接口必须对所有可能的构造类型都保持唯一。否则就无法确定该为某些构造类型调用哪个方法。

    说明:
    在实例化泛型时也可以使用约束类型参数的类型种类施加限制,约束是使用where上下文类关键字指定的。下面列出了6种类型的约束。
    ①、T:结构——类型参数必须是值类型。可以指定除Nullable以外的任何值类型。
    ②、T:类——类型参数必须是引用类型。这一点适用于任何类、接口、委托或数组类型。
    ③、T:new()——类型参数必须具有无参数的公共构造函数,当与其他约束一起使用时,new()约束必须是最后指定。
    ④、T:<基类名>——类型参数必须是指定的基类或派生自指定的基类。
    ⑤、T:<接口名称>——类型参数必须是指定的接口或实现指定的接口。可以指定多接口约束。约束接口也可以是泛型的。
    ⑥、T:U——为T提供的类型参数必须是为U提供的参数或派生自为U提供的参数。这称为裸类型的约束。

    实例如下:

namespace Test01
{
    //创建一个泛型接口
    public interface IGenericInterface<T>
    {
        T CreateInstance();								//接口中调用CreateInstance方法
    }
    //实现上面泛型接口的泛型类
    //派生约束where T : TI(T要继承自TI)
    //构造函数约束where T : new()(T可以实例化)
    public class Factory<T, TI> : IGenericInterface<TI> where T : TI, new()
    {
        public TI CreateInstance()							//创建一个公共方法CreateInstance
        {
            return new T();
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            //实例化接口
            IGenericInterface<System.ComponentModel.IListSource> factory = new Factory<System.Data.DataTable, System.ComponentModel.IListSource>();
            //输出指定泛型的类型
            Console.WriteLine(factory.CreateInstance().GetType().ToString());
            Console.ReadLine();
        }
    }
}

在这里插入图片描述

        1.2.3、泛型方法

        泛型方法的声明形式如下。
    【修饰符】 Void 【方法名】<类型参数T>
    {
        【方法体】
    }
    泛型方法是在声明中包括了类型参数T的方法。泛型方法可以在类、结构或接口声明中声明,这些类、结构或接口本身可以是泛型或非泛型。如果在泛型类型声明中声明泛型方法,则方法体可以同时引用该方法的类型参数T和包含该方法的声明的类型参数T。

    说明:
    泛型方法可以使用多类型参数进行重载。

    实例如下:

namespace Test02
{
    public class Finder										//建立一个公共类Finder
    {
        public static int Find<T>(T[] items, T item)					//创建泛型方法
        {
            for (int i = 0; i < items.Length; i++)						//调用for循环
            {
                if (items[i].Equals(item))							//调用Equals方法比较两个数
                {
                    return i;									//返回相等数在数组中的位置
                }
            }
            return -1;										//如果不存在指定的数,则返回-1
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            int i = Finder.Find<int>(new int[] { 1, 2, 3, 4, 5, 6, 8, 9 }, 6);	//调用泛型方法,并定义数组指定数字
            Console.WriteLine("6在数组中的位置:" + i.ToString());		//输出中数字在数组中的位置
            Console.ReadLine();
        }
    }
}

在这里插入图片描述

2、文件及数据流技术

        在软件开发过程中经常需要对文件及文件夹进行操作,例如读写、移动、复制、删除文件及创建、移动、删除、遍历文件夹等,在C#中与文件、文件夹及文件读写有关的类都位于System.IO命名空间下。

        2.1、System.IO命名空间

        System.IO命名空间包含允许在数据流和文件中进行同步和异步读写及写入的类型。这里需要注意文件和流的差异,文件是一些具有永久存储及特定顺序的字节组成的一个有序的、具有名称的集合,因此,关于文件,人们常会想到目录路径、磁盘存储、文件和目录名等方面。相反,流提供一种向后备存储写入字节和从后备存储读取字节的方式。后备存储可以为多种存储媒介之一,正如除磁盘外存在多种后备存储一样,除文件流之外也存在多种流。例如网络流、内存流和磁带流等。

        (System.IO命名空间中的类及说明)

        2.1.1、File类和Directory类

        File类和Directory类分别用来对文件和各种目录进行操作,这两个类可以被实例化,但不能被其他类继承。
    File类和Directory类就好比一个工厂,文件和文件夹就好比工厂所制作的产品,而工厂和产品的关系主要表现在一下几个方面:工厂可以自行开发产品(文件和文件夹的创建);也可以对该产品进行批量生产(文件和文件夹的复制);将产品进行销售(文件和文件夹的移动);以及将有质量问题的产品进行回收消除(文件和文件夹删除)。
    <1>、File类
     File类支持对文件的基本操作,它包括用于创建、复制、删除、移动和打开文件的静态方法,并协助创建FileStream对象。 File类中一共包含了40多个方法,这里只列出其常用的方法。

        (File类中的常用方法及说明)

        说明:
        ①、由于File类中的所有方法都是静态的,所以如果只想执行一个操作,那么使用File类中的方法的效率比使用相应的FileInfo类中的方法可能更高。
    ②、File类的静态方法对所有方法都执行安全检查,因此,如果打算多次重用某个对象,可考虑使用FileInfo类中的相应方法,因为并不总是需要安全检查。
    ③、使用与文件、文件夹及流相关的类时,首先需要添加System.IO命名空间。

    实例如下:

namespace Test03
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (textBox1.Text == string.Empty)        //判断输入的文件名是否为空
            {
                MessageBox.Show("文件名不能为空!");
            }
            else
            {
                if (File.Exists(textBox1.Text))       //使用File类的Exists方法判断要创建的文件是否存在
                {
                    MessageBox.Show("该文件已经存在");
                }
                else
                {
                    File.Create(textBox1.Text);       //使用File类的Create方法创建文件
                }
            }
        }
    }
}

在这里插入图片描述
        <2>、Directory类
    Directory类公开了用于创建、移动、枚举、删除目录和子目录的静态方法。 这里只列出其常用的方法。

        (Directory类中的常用方法及说明)

        说明:
        在用Directory类对文件夹进行操作时,其文件夹的路径必须正确,否则会触发异常。

    实例如下:

namespace Test04
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (textBox1.Text == string.Empty)                //判断输入的文件夹名称是否为空
            {
                MessageBox.Show("文件夹名称不能为空!");
            }
            else
            {
                if (Directory.Exists(textBox1.Text))          //使用Directory类的Exists方法判断要创建的文件夹是否存在
                {
                    MessageBox.Show("该文件夹已经存在");
                }
                else
                {
                    Directory.CreateDirectory(textBox1.Text);  //使用Directory类的CreateDirectory方法创建文件夹
                }
            }
        }
    }
}

在这里插入图片描述

        2.1.2、FileInfo类和DirectoryInfo类

        使用FileInfo类和DirectoryInfo类可以方便地对文件和文件夹进行操作。
    <1>、FileInfo类
    FileInfo类和File类之间许多方法调用都是相同的,但是FileInfo类没有静态方法,该类中的方法仅可以用于实例化的对象。File类是静态类,所以它的调用需要字符串参数为每一个方法调用规定文件位置。因此如果要在对象上进行单一方法调用,则可以使用静态File类,在这种情况下静态调用速度要快一些,因为.NET框架不必执行实例化对象并调用其方法的过程。如果要在文件上执行几种操作,则实例化FileInfo对象使用其方法就更好一些。这样会提高效率,因为对象将在文件系统上引用正确的文件,而静态类就必须每次都寻找文件。
    前面已用工厂对File类和Directory类进行讲解,这里还是以工厂对FileInfo类和DirectoryInfo类进行一下讲解。这两个类就好比工厂对产品(文件和文件夹)的记录清单,如产品名称(文件和文件夹的名称)、产品的库地址和销售商地址(文件和文件夹的目录)、产品的创建及检测时间(文件和文件夹的访问时间)、产品二次加工的时间(文件和文件夹的写入时间)以及当前产品为成品(文件只读)等。

        (FileInfo类中的常用属性及说明)
        说明:
        如果想要对某个对象进行重复操作,应使用FileInfo类。

    实例如下:

namespace Test05
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (textBox1.Text == string.Empty)           //判断输入的文件名称是否为空
            {
                MessageBox.Show("文件名称不能为空!");
            }
            else
            {
                FileInfo finfo = new FileInfo(textBox1.Text);
                if (finfo.Exists)                        //使用FileInfo对象的Exists属性判断要创建的文件是否存在
                {
                    MessageBox.Show("该文件已经存在");
                }
                else
                {
                    finfo.Create();                       //使用FileInfo对象的Create方法创建文件
                }
            }
        }
    }
}

在这里插入图片描述
        <2>、DirectoryInfo类
    DirectoryInfo类和Directory类之间的关系与FileInfo类和File类之间的关系十分类似,这里不再赘述。

        (DirectoryInfo类的常用属性及说明)
        
    实例如下:

namespace Test06
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (textBox1.Text == string.Empty)           //判断输入的文件夹名称是否为空
            {
                MessageBox.Show("文件夹名称不能为空!");
            }
            else
            {
                DirectoryInfo dinfo = new DirectoryInfo(textBox1.Text);  //实例化DirectoryInfo类对象
                if (dinfo.Exists)                        //使用DirectoryInfo对象的Exists属性判断要创建的文件夹是否存在
                {
                    MessageBox.Show("该文件夹已经存在");
                }
                else
                {
                    dinfo.Create();                      //使用DirectoryInfo对象的Create方法创建文件夹
                }
            }
        }
    }
}

在这里插入图片描述

        2.2、文件基本操作

        对于文件的基本操作大体可以分为判断文件是否存在、创建文件、复制或移动文件、删除文件以及获取文件基本信息。

        2.2.1、判断文件是否存在

        判断文件是否存在时,可以使用File类的Exists方法或者FileInfo类的Exists属性来实现,下面分别对它们进行介绍。
    <1>、File类的Exists方法
    确定指定的文件是否存在,语法如下。
    public static bool Exists (string path)
    path:要检查的文件
    返回值:如果调用方具有要求的权限并且path包含现有文件的名称,则为true;否则为false。如果path为空引用或零长度的字符串,则方法也返回false;如果调用方不具有读取指定文件所需的足够权限,则不引发异常并且该方法返回false,这与path是否存在无关。如果路径为空,则会触发异常。
    例子:
    File.Exists(“C:\Test.txt”);

    <2>、FileInfo类的Exists属性
    获取指示文件是否存在的值,语法如下。
    public override bool Exists { get; }
    例子:
    FileInfo finfo = new FileInfo(“C:\Test.txt”);
    if (finfo.Exists)
    {}

        2.2.2、创建文件

        创建文件可以使用File类的Create方法或者FileInfo类的Create方法来实现,下面分别对它们进行介绍。
    <1>、File类的Create方法
    该方法为可重载方法,它有以下4种重载形式。
    public static FileStream Create (string path)
    public static FileStream Create (string path,int bufferSize)
    public static FileStream Create (string path,int bufferSize,FileOptions options)
    public static FileStream Create (string path,int bufferSize,FileOptions options,FileSecurity fileSecurity);

        (File类的Create()方法参数说明)

        在用Create()方法创建目录时,如果路径为空,或文件夹为只读,则会触发异常。
    例子:
    File.Create(“C:\Test.txt”);

    <2>、FileInfo类的Create方法
    public FileStream Create()
    返回值:新文件,默认情况下,Create()方法将向所有用户授予对新文件的完全读写访问权限。
    例子:
    FileInfo finfo = new FileInfo(“C:\Test.txt”);
    finfo.Create();

        2.2.3、复制或移动文件

        复制或移动文件时,可以使用File类的Copy()方法、Move()方法或者FileInfo类的CopyTo()方法、MoveTo()方法来实现,下面分别对它们进行介绍。
    <1>、File类的Copy方法
    Copy()方法为可重载方法,它有以下两种重写形式。
    public static void Copy(string sourceFileName, string destFileName)
    public static void Copy(string sourceFileName, string destFileName, bool overwrite)
    sourceFileName:要复制的文件。
    destFileName:目标文件的名称,不能是目录。如果是第一种重载形式,则该参数不能是现有文件。
    overwrite:如果可以改写目标文件,则为true;否则为false。
    例如:
    File.Copy(“C:\Test.txt”,“D:\Test.txt”);

    <2>、File类的Move方法
    Move()方法可用于将指定文件移到新位置,并提供指定新文件名的选项,语法如下。
    public static void Move(string sourceFileName, string destFileName)
    sourceFileName:要移动的文件的名称。
    destFileName:文件的新路径。
    在对文件移动时,如果目标文件已存在,则发生异常。
    例如:
    File.Move(“C:\Test.txt”,“D:\Test.txt”) ;

    <3>、FileInfo类的CopyTo方法
    CopyTo()方法为可重载方法,它有以下两种重写形式。
    public FileInfo CopyTo(string destFileName)
    public FileInfo CopyTo(string destFileName, bool overwrite)
    destFileName:要复制到的新文件的名称。
    overwrite:若为true,则允许改写现有文件;否则为false。
    返回值:第一种重载形式的返回值为带有完全限定路径的新文件。第二种重载形式的返回值为新文件,或者如果overwrite为true,则为现有文件的改写。如果文件存在,且overwrite为false。则会发生IOException异常。
    例如:
    FileInfo finfo = new FileInfo(“C:\Test.txt”);
    finfo.CopyTo(“D:\Test.txt”,true);

    <4>、FileInfo类的MoveTo方法
    MoveTo()方法可用于将指定文件移到新位置,并提供指定新文件名的选项,语法如下。
    public void MoveTo(string destFileName)
    destFileName:要将文件移动到路径,可以指定另一个文件名。
    例如:
    FileInfo finfo = new FileInfo(“C:\Test.txt”);
    finfo. MoveTo(“D:\Test.txt”) ;

        2.2.4、删除文件

        删除文件可以使用File类的Delete()方法或者FileInfo类的Delete()方法来实现,下面分别对它们进行介绍。
    <1>、File类的Delete方法
    该方法是指删除指定的文件,语法如下。
    public static void Delete (string path)
    path:要删除的文件的名称。
    如果当前删除的文件正在被使用,删除时则发生异常。
    例子:
    File.Delete(“C:\Test.txt”);

    <2>、FileInfo类的Delete方法
    该方法是指永久删除文件,语法如下。
    public override void Delete()
    例子:
    FileInfo finfo = new FileInfo(“C:\Test.txt”);
    finfo. Delete ();

        2.2.5、获取文件的基本信息

        获取文件的基本信息时,主要用到了FileInfo类中的各种属性。下面通过一个实例说明如何获取文件的基本信息。

namespace Test07
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                textBox1.Text = openFileDialog1.FileName;
                FileInfo finfo = new FileInfo(textBox1.Text);         //实例化FileInfo对象
                string strCTime, strLATime, strLWTime, strName, strFName, strDName, strISRead;
                long lgLength;
                strCTime = finfo.CreationTime.ToShortDateString();    //获取文件创建时间
                strLATime = finfo.LastAccessTime.ToShortDateString(); //获取上次访问该文件的时间
                strLWTime = finfo.LastWriteTime.ToShortDateString();  //获取上次写入文件的时间
                strName = finfo.Name;                                 //获取文件名称
                strFName = finfo.FullName;                            //获取文件的完整目录
                strDName = finfo.DirectoryName;                       //获取文件的完整路径
                strISRead = finfo.IsReadOnly.ToString();              //获取文件是否只读
                lgLength = finfo.Length;                              //获取文件长度
                MessageBox.Show("文件信息:\n创建时间:" + strCTime + " 上次访问时间:" + strLATime + "\n上次写入时间:" + strLWTime + " 文件名称:" + strName + "\n完整目录:" + strFName + "\n完整路径:" + strDName + "\n是否只读:" + strISRead + " 文件长度:" + lgLength);
            }
        }
    }
}

在这里插入图片描述

        2.3、文件夹的基本操作

        对于文件夹的基本操作大体可以分为判断文件夹是否存在、创建文件夹、移动文件夹、删除文件夹以及遍历文件夹中的文件。

        2.3.1、判断文件夹是否存在

        判断文件夹是否存在时,可以使用Directory类的Exists()方法或者DirectoryInfo类的Exists属性来实现,下面分别对它们进行介绍。
    <1>、Directory类的Exists方法
    确定给定路径是否引用磁盘上的现有目录,语法如下。
    public static bool Exists (string path)
    path:要测试的路径
    返回值:如果path引用现有目录,则为true;否则为false。
    允许path参数指定相对或绝对路径。相对路径信息被解释为相对于当前的工作目录。
    例子:
    Directory.Exists("C:\Test ");

    <2>、DirectoryInfo类的Exists属性
    获取指示目录是否存在的值,语法如下。
    public override bool Exists { get; }
    属性值:如果目录存在,则为true;否则为false。
    例子:
    DirectoryInfo dinfo = new DirectoryInfo (“C:\Test”);
    if (dinfo.Exists)
    {}

        2.3.2、创建文件夹

        创建文件夹可以使用Directory类的CreateDirectory()方法或者DirectoryInfo类的Create()方法来实现,下面分别对它们进行介绍。
    <1>、Directory类的CreateDirectory方法
    该方法为可重载方法,它有以下两种重载形式。
    public static DirectoryInfo CreateDirectory (string path)
    public static DirectoryInfo CreateDirectory (string path,DirectorySecurity directorySecurity)
    path:要创建的目录路径。
    directorySecurity:要应用于此目录的访问控制。
    返回值:第一种重载形式的返回值为由path指定的DirectoryInfo;第二种重载形式的返回值为新创建的目录的DirectoryInfo对象。
    当path参数中的目录已经存在或者path的某些部分无效时,将发生异常。path参数指定目录路径,而不是文件路径。
    例子:
    Directory. CreateDirectory ("C:\Test ");

    <2>、DirectoryInfo类的Create方法
    该方法为可重载方法,它有以下两种重载形式。
    public void Create ()
    public void Create (DirectorySecurity directorySecurity)
    directorySecurity:主要应用于此目录的访问控制。
    例子:
    DirectoryInfo dinfo = new DirectoryInfo ("C:\Test ");
    dinfo.Create();

        2.3.3、移动文件夹

        移动文件夹时,可以使用Directory类的Move()方法或者DirectoryInfo类的MoveTo()方法来实现,下面分别对它们进行介绍。
    <1>、Directory类的Move方法
    将文件或目录及其内容移到新位置,语法如下
    public static void Move (string sourceDirName,string destDirName)
    sourceDirName:要移动的文件或目录的路径。
    destDirName:指向sourceDirName的新位置的路径。
    使用Move()方法移动文件夹时需要同一磁盘根路径,例如,C盘下的文件只能移动到C盘中的某个文件夹下。同样,使用MoveTo()方法移动文件夹时也是如此。
    例子:
    Directory.Move("C:\Test ",“C:\新建文件夹\Test”);

    <2>、DirectoryInfo类的MoveTo方法
    将DirectoryInfo对象及其内容移动到新路径,语法如下。
    public void MoveTo (string destDirName)
    destDirName:要将此目录移动到的目标位置的名称和路径。目标不能是另一个具有相同名称的磁盘卷或目录,他可以是要将此目录作为子目录添加到其中的一个现有目录中。
    例子:
    DirectoryInfo dinfo = new DirectoryInfo ("C:\Test ");
    dinfo. MoveTo(“C:\新建文件夹\Test”);

        2.3.4、删除文件夹

        删除文件夹可以使用Directory类的Delete()方法或者DirectoryInfo类的Delete()方法来实现,下面分别对它们进行介绍。
    <1>、Directory类的Delete方法
    该方法为可重载方法,它有以下两种重载形式。
    public static void Delete (string path)
    public static void Delete (string path,bool recursive)
    path:要移除的空目录/目录的名称。
    recursive:若要移除path中的目录、子目录和文件,则为true;否则为false。
    例子:
    Directory.Delete(“C:\Test”);

    <2>、DirectoryInfo类的Delete方法
    该方法是指永久删除文件,语法如下。
    public override void Delete ()
    public void Delete (bool recursive)
    recursive:若为true,则删除此目录、其子目录以及所有文件;否则为false。
    第一种重载形式,如果DirectoryInfo为空,则删除它;第二种重载形式,删除DirectoryInfo对象,并指定是否要删除子目录和文件。
    例子:
    DirectoryInfo dinfo = new DirectoryInfo (“C:\Test”);
    dinfo.Delete ();

        2.3.5、遍历文件夹

        遍历文件夹时,可分别使用DirectoryInfo类提供的GetDirectories()方法、GetFile()方法和GetFileSystemInfos()方法。下面对这3个方法进行相机讲解。
    <1>、GetDirectories方法
    该方法用来返回当前目录的子目录。该方法为可重载方法,它有以下3种重载形式。
    public DirectoryInfo[] GetDirectories ()
    public DirectoryInfo[] GetDirectories (string searchPattern)
    public DirectoryInfo[] GetDirectories (string searchPattern,SearchOption searchOption)
    searchPattern:搜索字符串,如用于搜索所有以单词System开头的目录的“System*”。
    searchOption:SearchOption枚举的一个值,指定搜索操作时应仅包含当前目录还是应包含素有子目录。
    返回值:第一种重载形式的返回值为DirectoryInfo对象的数组;第二种和第三种重载形式的返回值为与searchPattern匹配的DirectoryInfo类型的数组。

    <2>、GetFiles方法
    返回当前目录的文件列表。该方法为可重载方法,它有以下3种重载形式。
    public FileInfo[] GetFiles ()
    public FileInfo[] GetFiles (string searchPattern)
    public FileInfo[] GetFiles (string searchPattern,SearchOption searchOption)
    searchPattern:搜索字符串(如:“*.txt”)。
    searchOption:SearchOption枚举的一个值,指定搜索操作是应仅包含当前目录还是应包含所有目录。
    返回值:FileInfo类型数组。

    <3>、GetFileSystemInfos方法
    返回表示某个目录中所有文件和子目录的FileSystemInfo类型数组。该方法为可重载方法,它有以下两种重载形式。
    public FileSystemInfo[] GetFileSystemInfos ()
    public FileSystemInfo[] GetFileSystemInfos (string searchPattern)
    searchPattern:搜索字符串。
    返回值:第一种重载形式的返回值为FileSystemInfo项的数组;第二种重载形式的返回值为与搜索条件匹配的FileSystemInfo对象的数组。
    一般遍历文件夹时,都是用GetFileSystemInfos()方法,因为GetDirectories()方法只遍历文件夹中的子文件夹,GetFiles()方法只遍历文件夹中的文件,而GetFilesSystemInfos()方法遍历文件夹中的所有子文件夹及文件。

    实例如下:

namespace Test08
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            listView1.Items.Clear();
            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
            {
                textBox1.Text = folderBrowserDialog1.SelectedPath;
                //实例化DirectoryInfo对象
                DirectoryInfo dinfo = new DirectoryInfo(textBox1.Text);
                //获取指定目录下的所有子目录及文件类型
                FileSystemInfo[] fsinfos = dinfo.GetFileSystemInfos();
                foreach (FileSystemInfo fsinfo in fsinfos)
                {
                    if (fsinfo is DirectoryInfo)    //判断是否文件夹
                    {
                        //使用获取的文件夹名称实例化DirectoryInfo对象
                        DirectoryInfo dirinfo = new DirectoryInfo(fsinfo.FullName);
                        //为ListView控件添加文件夹信息
                        listView1.Items.Add(dirinfo.Name);
                        listView1.Items[listView1.Items.Count - 1].SubItems.Add(dirinfo.FullName);
                        listView1.Items[listView1.Items.Count - 1].SubItems.Add("");
                        listView1.Items[listView1.Items.Count - 1].SubItems.Add(dirinfo.CreationTime.ToShortDateString());
                    }
                    else
                    {
                        //使用获取的文件名称实例化FileInfo对象
                        FileInfo finfo = new FileInfo(fsinfo.FullName);
                        //为ListView控件添加文件信息
                        listView1.Items.Add(finfo.Name);
                        listView1.Items[listView1.Items.Count - 1].SubItems.Add(finfo.FullName);
                        listView1.Items[listView1.Items.Count - 1].SubItems.Add(finfo.Length.ToString());
                        listView1.Items[listView1.Items.Count - 1].SubItems.Add(finfo.CreationTime.ToShortDateString());
                    }
                }
            }
        }
    }
}

在这里插入图片描述

        2.4、数据流

        数据流提供了一种向后存储写入字节和从后备存储读取字节的方式,它是在.NET Framework中执行读写文件操作时一种非常重要的介质。

        2.4.1、流操作类介绍

        .NET Framework使用流来支持读取和写入文件,开发人员可以将流视为一组连续的一维数据,包含开头和结尾,并且其中的游标指示了流中的当前位置。
    <1>、流操作
    流中包含的数据可能来自内存、文件或TCP/IP套接字。流包含以下几种可应用于自身的基本操作。
    读取:将数据从流传输到数据结构(如字符串或字节数组)中。
    写入:将数据从数据源传输到流中。
    查找:查询和修改在流中的位置。
    <2>、流的类型
    在.NET Framework中,流由Stream类来表示,该类构成了所有其他流的抽象类。不能直接创建Stream类的实例,但是必须使用它实现其中的一个类。
    C#中有许多类型的流,但在处理文件输入/输出(I/O)时,最重要的类型是FileStream类,它提供了读取和写入文件的方式。可在处理文件I/O时使用的其他流主要包括BufferedStream、CryptoStream、MemoryStream和NetworkStream等。

        2.4.2、文件流类

        FileStream类公开以文件为主的Stream,它表示在磁盘或网络路径上指向文件的流。一个FileStream类的实例实际上代表一个磁盘文件,它通过Seek方法进行对文件的随机访问,也同时包含了流的标准输入、标准输出、标准错误等。FileStream默认对文件的打开方式是同步的,但它同样很好地支持异步操作。
    对文件流的操作,实际上可以将文件看作是电视信号发送塔要发送的一个电视节目(文件),将电视节目转换成模拟数字信号(文件的二进制流),按指定的发送序列发送到指定的接受地点(文件的接收地址)。
    FileStream对象支持使用Seek()方法对文件进行随机访问。Seek允许将读取/写入位置移动到文件中的任意位置。
    <1>、FileStream类的常用属性

        (FileStream类的常用属性及说明)

        <2>、FileStream类的常用方法

        (FileStream类的常用方法及说明)

        <3>、FileStream类操作文件
    要用FileStream类操作文件就要先实例化一个FileStream对象,FileStream类的构造函数具有许多不同的重载形式,其中包括了一个最重要的参数,即FileMode枚举。

        (FileMode类的枚举成员及说明)

        例子:
    FileStream aFile = new FileStream(“Test.txt”,FileMode.OpenOrCreate, FileAccess.ReadWrite)

        2.4.3、文本文件的写入与读取

        文本文件的写入与读取主要是通过StreamWrite类和StreamReader类来实现的,下面对这两个类进行详细讲解。
    <1>、StreamWriter类
    StreamWriter是专门用来处理文本文件的类,可以方便地向文本文件中写入字符串。同时也负责重要的转换和处理向FileStream对象写入工作。
    StreamWriter类默认使用UTF8Encoding编码来进行实例化。

        (StreamWriter类的常用属性及说明)

        (StreamWriter类的常用方法及说明)

        <2>、StreamReader类
    StreamReader是专门用来读取文本文件的类,StreamReader可以从底层Stream对象创建StreamReader对象的实例,而且也能指定编码规范参数。创建StreamReader对象后,它提供了许多用于读取和浏览字符数据的方法。

        (StreamReader类的常用方法及说明)

        实例如下:

namespace Test09
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (textBox1.Text == string.Empty)
            {
                MessageBox.Show("要写入的文件内容不能为空");
            }
            else
            {
                //设置保存文件的格式
                saveFileDialog1.Filter = "文本文件(*.txt)|*.txt";
                if (saveFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    //使用“另存为”对话框中输入的文件名实例化StreamWriter对象
                    StreamWriter sw = new StreamWriter(saveFileDialog1.FileName, true);
                    //向创建的文件中写入内容
                    sw.WriteLine(textBox1.Text);
                    //关闭当前文件写入流
                    sw.Close();
                    textBox1.Text = string.Empty;
                }
            }
        }
        private void button2_Click(object sender, EventArgs e)
        {
            //设置打开文件的格式
            openFileDialog1.Filter = "文本文件(*.txt)|*.txt";
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                textBox1.Text = string.Empty;
                //使用“打开”对话框中选择的文件实例化StreamReader对象
                StreamReader sr = new StreamReader(openFileDialog1.FileName);
                //调用ReadToEnd方法读取选中文件的全部内容
                textBox1.Text = sr.ReadToEnd();
                //关闭当前文件读取流
                sr.Close();
            }
        }
    }
}

在这里插入图片描述

        2.4.4、二进制文件的写入与读取

        二进制文件的写入与读取主要是通过BinaryWriter类和BinaryReader类来实现的,下面对这两个类进行详细讲解。
    <1>、BinaryWriter类
    BinaryWriter类以二进制形式将基元类型写入流,并支持用特定的编码写入字符串,其常用的方法及说明如下:

        (BinaryWriter类的常用方法及说明)

        <2>、BinaryReader类
    BinaryReader用特定的编码将基元数据类型读作二进制值,其常用的方法及说明如下:

        (BinaryReader类的常用方法及说明)

        实例如下:

namespace Test10
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (textBox1.Text == string.Empty)
            {
                MessageBox.Show("要写入的文件内容不能为空");
            }
            else
            {
                //设置保存文件的格式
                saveFileDialog1.Filter = "二进制文件(*.dat)|*.dat";
                if (saveFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    //使用“另存为”对话框中输入的文件名实例化FileStream对象
                    FileStream myStream = new FileStream(saveFileDialog1.FileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
                    //使用FileStream对象实例化BinaryWriter二进制写入流对象
                    BinaryWriter myWriter = new BinaryWriter(myStream);
                    //以二进制方式向创建的文件中写入内容
                    myWriter.Write(textBox1.Text);
                    //关闭当前二进制写入流
                    myWriter.Close();
                    //关闭当前文件流
                    myStream.Close();
                    textBox1.Text = string.Empty;
                }
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            //设置打开文件的格式
            openFileDialog1.Filter = "二进制文件(*.dat)|*.dat";
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                textBox1.Text = string.Empty;
                //使用“打开”对话框中选择的文件名实例化FileStream对象
                FileStream myStream = new FileStream(openFileDialog1.FileName, FileMode.Open, FileAccess.Read);
                //使用FileStream对象实例化BinaryReader二进制写入流对象
                BinaryReader myReader = new BinaryReader(myStream);
                if (myReader.PeekChar() != -1)
                {
                    //以二进制方式读取文件中的内容
                    textBox1.Text = Convert.ToString(myReader.ReadString());
                }
                //关闭当前二进制读取流
                myReader.Close();
                //关闭当前文件流
                myStream.Close();
            }
        }
    }
}

在这里插入图片描述


System.IO命名空间中的类及说明

说明
BinaryReader用特定的编码将基元数据类型读作二进制值
BinaryWriter以二进制形式将基元类型写入流,并支持用特定的编码写入字符串
BufferedStream给另一流上的读写操作添加一个缓冲层。无法继承此类
Directory公开用于创建、移动、枚举、删除目录和子目录的静态方法。无法继承此类
DirectoryInfo公开用于创建、移动和枚举目录和子目录的实例方法。无法继承此类
DriveInfo提供对有关驱动器的信息的访问
File提供用于创建、复制、删除、移动和打开文件的静态方法,并协助创建FileStream对象
FileInfo提供创建、复制、删除、移动和打开文件的实例方法,并且帮助创建FileStream对象。无法继承此类
FileStream公开以文件为主的Stream,即支持同步读写操作,也支持异步读写操作
FileSystemInfo为FileInfo和DirectoryInfo对象提供基类
FileSystemWatcher侦听文件系统更改通知,并在目录或目录中的文件发生更改时引发事件
MemoryStream创建其支持存储区为内存的流
Path对包含文件或目录路径信息的String实例执行操作。这些操作是以跨平台的方式执行的
StreamReader实现一个TextReader,使其以一种特定的编码从字节流中读取字符
StreamWriter实现一个TextWriter,使其以一种特定的编码向流中写入字符
StringReader实现从字符串进行读取的TextReader
stringWriter实现一个用于将信息写入字符串的TextWriter。该信息存储在基础StringBuilder中
TextReader表示可读取联系字符系列的读取器
TextWriter表示可以编写一个有序字符系列的编写器。该类为抽象类


File类中的常用方法及说明

方法说明
Copy将现有文件复制到新文件
Create在指定路径中创建文件
Delete删除指定的文件。如果指定的文件不存在,则不引发异常
Exists确定指定的文件是否存在
Move将指定文件移动到新位置,并提供指定新文件名的选项
Open打开指定路径上的FileStream
CreateText创建或打开一个文件用于写入UTF-8编辑文本
GetCreationTime返回指定文件或目录的创建日期和时间
GetLastAccessTime返回上次访问指定文件或目录的日期和时间
GetLastWriteTime返回上次写入指定文件或目录的日期和时间
OpenRead打开现有文件以进行读取
OpenText打开现有UTF-8编码文本文件以进行读取
OpenWrite打开现有文件以进行写入
readAllBytes打开一个文件,将文件的内容写入一个字符串,然后关闭该文件
readAllLines打开一个文本文件,将文件的所有行都读入一个字符串数组,然后关闭该文件
readAllText打开一个文本文件,将文件的所有行读入一个字符串,然后关闭该文件
Replace使用其他文本的内容替换指定文件的内容,这一过程将删除原始文件,并创建被替换文件的备份
SetCreationTime设置创建该文件的日期和时间
SetLastAccessTime设置上次访问指定文件的日期和时间
SetLastWriteTime设置上次写入指定文件的日期和时间
WriteAllBytes创建一个新文件,在其中写入指定的字节数组,然后关闭该文件。如果目标文件已存在,则改写该文件
WriteAllLines创建一个新文件,在其中写入指定的字符串,然后关闭文件。如果目标文件已存在,则改写该文件
WriteAllText创建一个新文件,在文件中写入内容,然后关闭文件。如果目标文件已存在,则改写该文件


Directory类中的常用方法及说明

方法说明
CreateDirectory创建指定路径中的所有目录
Delete删除指定的目录
Exists确定给定路径是否引用磁盘上的现有目录
GetCreationTime获取目录的创建日期和时间
GetDirectories获取指定目录中子目录的名称
GetDirectoryRoot获取指定路径的卷信息、根信息或二者同时返回
GetFiles返回指定目录中的文件的名称
GetFileSystemEntries返回指定目录中所有文件和子目录的名称
GetLastAccessTime返回上次访问指定文件或目录的日期和时间
GetLastWriterTime返回上次写入指定文件或目录的日期和时间
GetParent检索指定路径的父目录,包括绝对路径和相对路径
Move将文件或目录及其内容移到新位置
SetCreationTime为指定的文件或目录设置创建日期和时间
SetCurrentDirectory将应用程序的当前工作目录设置为指定目录
SetLastAccessTime设置上次访问指定文件或目录的日期和时间
SetLastWriteTime设置上次写入目录的日期和时间


FileInfo类中的常用属性及说明

属性说明
CreationTime获取或设置当前FileSystemInfo对象的创建时间
Directory获取父目录的实例
DirectoryName获取表示目录的完整路径的字符串
Exists获取指示文件是否存在的值
Extension获取表示文件扩展名部分的字符串
FullName获取目录或文件的完整目录
IsReadOnly获取或设置确定当前文件是否为只读的值
LastAccessTime获取或设置上次访问当前文件或目录的时间
LastWriteTime获取或设置上次写入当前文件或目录的时间
Length获取当前文件大小
Name获取文件名


DirectoryInfo类的常用属性及说明

属性说明
CreationTime获取或设置当前FileSystemInfo对象的创建时间
Exists获取指示目录是否存在的值
Extension获取表示文件扩展名部分的字符串
FullName获取目录或文件的完整目录
LassAccessTime获取或设置上次访问当前文件或目录的时间
LastWriteTime获取或设置上次写入当前文件或目录的时间
Name获取DirectoryInfo实例的名称
Parent获取指定子目录的父目录
Root获取路径的根部分


File类的Create()方法参数说明

参数说明
path文件名
bufferSize用于读取和写入文件的已放入缓冲区的字节数
optionsFileOptions值之一,它描述如何创建或改写该文件
fileSecurityFileSecurity值之一,它确定文件的访问控制和审核安全性


FileStream类的常用属性及说明

属性说明
CanRead获取一个值,该值指示当前流是否支持读取
CanSeek获取一个值,该值指示当前流是否支持查找
CanTimeout获取一个值,该值确定当前流是否可以超时
CanWrite获取一个值,该值指示当前流是否支持写入
IsAsync获取一个值,该值只是FileStream是异步还是同步打开的
Length获取用字节表示的流长度
Name获取传递给构造函数的FileStream的名称
Position获取或设置此流的当前位置
ReadTimeout获取或设置一个值,该值确定流在超时前尝试读取多长时间
WriteTimeout获取或设置一个值,该值确定流在超时前尝试写入多长时间


FileStream类的常用属性及说明

方法说明
BeginRead开始异步读操作
BeginWrite开始异步写操作
Close关闭当前流并释放与之关联的所有资源
EndRead等待挂起的异步读取完成
EndWrite结束异步写入,在I/O操作完成之前一直阻止
Lock允许读取访问的同时防止其他进程更改FileStream
Read从流中读取字节块并将该数据写入给定的缓冲区中
ReadByte从文件中读取一个字节,并将读取位置提升一个字节
Seek将该流的当前位置设置为给定值
SetLength将该流的长度设置为给定值
Unlock允许其他进程访问以前锁定的某个文件的全部或部分
Write使用从缓冲区读取的数据将字节块写入该流
WriteByte将一个字节写入文件流的当前位置


FileMode类的枚举成员及说明

枚举成员说明
Append打开现有文件并查找到文件尾,或创建新文件。FileMode.Append只能同FileAccess.Write一起使用。在任何读尝试都将失败并引发ArgumentException
Create指定操作系统应创建新文件。如果文件已存在,则它将被改写。这要求FileIOPermissionAccess.Write。System.IO.FileMode.Create等效与这样的请求:如果文件不存在,则使用CreateNew:否则使用Truncate
CreateNew指定操作系统应创建新文件。此操作需要FileIOPermissionAccess.Write。如果文件已存在,则将引发IOException
Open指定操作系统应打开现有文件。打开文件的能力取决于FileAccess所指定的值。如果该文件不存在,则引发System.IO.FileNotFoundException
OpenOrCreate指定操作系统应打开文件(如果文件存在);否则,应创建新文件。如果用FileAccess.Read打开文件,则需要FileIOPermissionAccess.Read;如果文件访问为FileAccess.Write或FileAccess.ReadWrite,则需要FileIOPermissionAccess.Write;如果文件访问为FileAccess.Append,则需要FileIOPermissionAccess.Append
Truncate指定操作系统应打开现有文件。文件一旦打开,就将被截断为零字节大小。此操作需要FileIOPermissionAccess.Write。试图从使用Truncate打开的文件中进行读取将导致异常


StreamWriter类的常用属性及说明

属性说明
Encoding获取将输出写入其中的Encoding中
Formatprovider获取控制格式设置的对象
NewLine获取或设置由当前TextWriter使用的行结束符字符串


StreamWriter类的常用方法及说明

方法说明
Close关闭当前的StringWriter和基础流
Write写入StringWriter的此实例中
WriteLine写入重载参数指定的某些数据,后跟行结束符


StreamReader类的常用方法及说明

方法说明
Close关闭StringReader
Read读取输入字符串中的下一个字符或下一组字符
ReadBlock从当前流中读取最大count的字符并从index开始将数据写入Buffer
ReadLine从基础字符串中读取一行
ReadToEnd将整个流或从流的当前位置到流的结尾作为字符串读取


BinaryWriter类的常用方法及说明

方法说明
Close关闭当前的BinaryWriter类和基础流
Seek设置当前流中的位置
Write将值写入当前流


BinaryReader类的常用方法及说明

方法说明
Close关闭当前阅读器及基础流
PeekChar返回下一个可用的字符,并且不提升字节或字符的位置
Read从基础流中读取字符,并提升流的当前位置
ReadBoolean从当前流中读取Boolean值,并使该流的当前位置提升一个字节
ReadByte从当前流中读取下一个字节,并使流的当前位置提升一个字节
ReadBytes从当前流中将count个字节读入字节数组,并使当前位置提升count个字节
ReadChar从当前流中读取下一个字符,并根据所使用的Encoding和从流中读取的特定字符,提升流的当前位置
ReadChars从当前流中读取count个字符,以字符数组的形式返回数据,并根据所使用的Encoding和从流中读取的特定字符,提升当前位置
ReadInt32从当前流中读取4个字节的有符号整数,并使流的当前位置提升4个字节
ReadString从当前流中读取一个字符串。字符串有长度前缀,一次将7位编码为整数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

扑腾的菜鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值