第12章 文件操作 12.1 文件和System.IO模型概述 12.2 System.IO模型 12.3 文件夹和文件操作 第12章 文件操作 12.1 文件和System.IO模型概述 12.2 System.IO模型 12.3 文件夹和文件操作 12.4 FileStream类 12.5 文本文件的操作 12.6 二进制文件操作 12.7 序列化和反序列化
12.1 文件和System.IO模型概述 1.1.1 文件类型 (1)按文件的存取方式及结构,文件可以分为顺序文件和随机文件 (1)按文件的存取方式及结构,文件可以分为顺序文件和随机文件 (2)按文件数据的组织格式,文件可分为ASCII文件和二进制文件
1.1.2 文件的属性 (1)文件属性:只读、隐藏和归档等类型。 (2)访问方式:读、读/写和写等类型。 (1)文件属性:只读、隐藏和归档等类型。 (2)访问方式:读、读/写和写等类型。 (3)访问权限:读、写、追加数据等类型。 (4)共享权限:文件共享、文件不共享等类型。
12.1.3 文件访问方式 在C#中可以通过.NET的System.IO模型以流的方式对各种数据文件进行访问。
12.2 System.IO模型 12.2.1 什么是System.IO模型 System.IO模型提供了一个面向对象的方法来访问文件系统。System.IO模型提供了很多针对文件、文件夹的操作功能,特别是以流(Stream)的方式对各种数据进行访问,这种访问方式不但灵活,而且可以保证编程接口的统一。
System. IO模型的实现包含在System System.IO模型的实现包含在System.IO命名空间中,该命名空间包含允许读写文件和数据流的类型以及提供基本文件和文件夹支持的各种类. 也就是说,System.IO模型是一个文件操作类库,包含的类可用于文件的创建、读/写、复制、移动和删除等操作,其中最常用的类如表12.1所示。
表12.1 System.IO命名空间中常用的类及其说明 说 明 BinaryReader 用特定的编码将基元数据类型读作二进制值 BinaryWriter 以二进制形式将基元类型写入流,并支持用特定的编码写入字符串 BufferedStream 给另一流上的读写操作添加一个缓冲层。无法继承此类 Directory 公开用于创建、移动和枚举通过目录和子目录的静态方法。无法继承此类 DirectoryInfo 公开用于创建、移动和枚举目录和子目录的实例方法。无法继承此类 DriveInfo 提供对有关驱动器的信息的访问 File 提供用于创建、复制、删除、移动和打开文件的静态方法,并协助创建FileStream对象 FileInfo 提供创建、复制、删除、移动和打开文件的实例方法,并且帮助创建 FileStream 对象,无法继承此类
FileStream 公开以文件为主的Stream,既支持同步读写操作,也支持异步读写操作 Path 对包含文件或目录路径信息的 String 实例执行操作。这些操作是以跨平台的方式执行 Stream 提供字节序列的一般视图 StreamReader 实现一个TextReader,使其以一种特定的编码从字节流中读取字符 StreamWriter 实现一个TextWriter,使其以一种特定的编码向流中写入字符 StringReader 实现从字符串进行读取的TextReader StringWriter 实现一个用于将信息写入字符串的 TextWriter。该信息存储在基础 StringBuilder 中。 TextReader 表示可读取连续字符系列的读取器。 TextWriter 表示可以编写一个有序字符系列的编写器。该类为抽象类
12.2.2 文件编码 文件编码也称为字符编码,用于指定在处理文本时如何表示字符。一种编码可能优于另一种编码,主要取决于它能处理或不能处理哪些语言字符,不过通常首选的是Unicode。 表12.2列出了该类的属性及其对应文件编码方式。
表12.2 文件编码类型及其说明 编码 说 明 ASCII 获取ASCII(7位)字符集的编码 Default 说 明 ASCII 获取ASCII(7位)字符集的编码 Default 获取系统的当前ANSI代码页的编码 Unicode 获取使用Little-Endian字节顺序的UTF-16格式的编码 UTF32 获取使用Little-Endian字节顺序的UTF-32格式的编码 UTF7 获取UTF-7格式的编码 UTF8 获取UTF-8格式的编码
12.2.3 C#的文件流 C#将文件看成是顺序的字节流,也称为文件流。 文件流是字节序列的抽象概念,文件可以看成是存储在磁盘上的一系列二进制字节信息。 C#用文件流对其进行输入、输出操作,例如,读取文件信息、向文件写入信息。 C#提供Stream类(System.IO成员)是所有流的基类,由它派生出文件流FileStream和缓冲区流BufferedStream。
12.3 文件夹和文件操作 12.3.1 文件夹操作 Directory类提供了文件夹操作的方法,表12.3列出了Directory类的常用方法。Directory类内的方法是共享的,无须创建对象实体即可使用。
表12.3 Directory类的常用方法及其说明 说 明 CreateDirectory 创建所有目录或子目录 Delete 从指定路径删除目录 Exists 返回值确定给定路径是否现有目录 GetCreationTime 返回指定目录的创建日期和时间 GetCurrentDirectory 返回应用程序的当前工作目录 GetDirectories 返回值为指定目录中子目录的名称 GetFiles 返回指定目录中的文件的名称
GetFileSystemEntries 返回指定目录中所有文件和子目录的名称 GetLastAccessTime 返回上次访问指定文件或目录的日期和时间 GetLastWriteTime 返回上次写入指定文件或目录的日期和时间 GetLogicalDrives 返回此计算机上格式为“驱动器号:\”的逻辑驱动器的名称 GetParent 返回指定路径的父目录 Move 将文件或目录及其内容移到新位置 SetCreationTime 为指定的文件或目录设置创建日期和时间 SetCurrentDirectory 将应用程序的当前工作目录设置为指定的目录 SetLastAccessTime 设置上次访问指定文件或目录的日期和时间 SetLastWriteTime 设置上次写入目录的日期和时间
12.3.2 文件操作 File类提供了文件操作的方法,并协助创建FileStream对象。File类的常用方法如表12.4所示。 12.3.2 文件操作 File类提供了文件操作的方法,并协助创建FileStream对象。File类的常用方法如表12.4所示。 和Directory类一样,File类的方法是共享的,无须创建对象实体即可使用。
表12.4 File类的常用方法及其说明 File类的方法 说 明 AppendAllText 说 明 AppendAllText 将指定的字符串追加到文件中,如果文件还不存在则创建该文件 AppendText 创建一个StreamWriter,它将UTF-8编码文本追加到现有文件中 Copy 将现有文件复制到新文件中 Create 在指定路径中创建文件 CreateText 创建或打开一个文件用于写入UTF-8编码的文本 Delete 删除指定的文件。如果指定的文件不存在,则不引发异常 Exists 确定指定的文件是否存在 GetAttributes 获取在此路径上的文件的FileAttributes GetCreationTime 返回指定文件或目录的创建日期和时间 GetLastAccessTime 返回上次访问指定文件或目录的日期和时间
GetLastWriteTime 返回上次写入指定文件或目录的日期和时间 Move 将指定文件移到新位置,并提供指定新文件名的选项 Open 打开指定路径上的FileStream OpenRead 打开现有文件以进行读取 OpenText 打开现有UTF-8编码文本文件以进行读取 OpenWrite 打开现有文件以进行写入 ReadAllBytes 打开一个文件,将文件的内容读入一个字符串,然后关闭该文件 ReadAllLines 打开一个文本文件,将文件的所有行都读入一个字符串数组,然后关闭该文件 ReadAllText 打开一个文本文件,将文件的所有行读入一个字符串,然后关闭该文件 Replace 使用其他文件的内容替换指定文件的内容,这一过程将删除原始文件,并创建被替换文件的备份
【例12.1】 设计一个窗体,显示指定目录中的所有文件的文件名、创建时间和文件属性。 Form1,设计界面
事件过程: private void button1_Click(object sender, EventArgs e) { int i; string[] filen; string filea; listBox1.Items.Clear(); if (!Directory.Exists(textBox1.Text)) MessageBox.Show(textBox1.Text + "文件夹不存在", "信息提示",MessageBoxButtons.OK); else { filen = Directory.GetFiles(textBox1.Text); for (i = 0; i <= filen.Length - 1; i++) { filea = String.Format("{0}\t{1} {2}",filen[i], File.GetCreationTime(filen[i]),fileatt(filen[i])); listBox1.Items.Add(filea); }
private string fileatt(string filename) //获取文件属性 { string fa=""; switch(File.GetAttributes(filename)) { case FileAttributes.Archive: fa="存档"; break; case FileAttributes.ReadOnly: fa="只读"; break; case FileAttributes.Hidden: fa="隐藏"; break; case FileAttributes.Archive | FileAttributes.ReadOnly: fa="存档+只读"; break; case FileAttributes.Archive | FileAttributes.Hidden: fa="存档+隐藏"; break; case FileAttributes.ReadOnly | FileAttributes.Hidden: fa="只读+隐藏"; break; case FileAttributes.Archive | FileAttributes.ReadOnly | FileAttributes.Hidden: fa="存档+只读+隐藏"; break; } return fa;
运行界面
12.4 FileStream类 使用FileStream类可以产生文件流,以便对文件进行读取、写入、打开和关闭操作。FileStream类提供的构造函数很多,最常用的构造函数如下: public FileStream(string path,FileMode mode) 它使用指定的路径和创建模式初始化FileStream类的新实例。其中,path指出当前FileStream对象封装的文件的相对路径或绝对路径。mode指定一个FileMode常数,确定如何打开或创建文件。
FileMode常数的说明如表12.5所示。 成员名称 说 明 Append 说 明 Append 打开现有文件并查找到文件尾,或创建新文件。FileMode.Append只 能同FileAccess.Write一起使用 Create 指定操作系统应创建新文件。如果文件已存在,它将被改写。如果文 件不存在,则使用CreateNew;否则使用Truncate CreateNew 指定操作系统应创建新文件 Open 指定操作系统应打开现有文件 OpenOrCreate 指定操作系统应打开文件(如果文件存在);否则,应创建新文件 Truncate 指定操作系统应打开现有文件。文件一旦打开,就将被截断为零字节 大小
成员名称 说 明 Append 打开现有文件并查找到文件尾,或创建新文件。 FileMode.Append只能同FileAccess.Write一起使用 Create 指定操作系统应创建新文件。如果文件已存在,它将被改写。 如果文件不存在,则使用CreateNew;否则使用Truncate CreateNew 指定操作系统应创建新文件 Open 指定操作系统应打开现有文件 OpenOrCreate 指定操作系统应打开文件(如果文件存在);否则,应创建新 文件 Truncate 指定操作系统应打开现有文件。文件一旦打开,就将被截断为 零字节大小
12.5 文本文件的操作 文本文件的操作通过StreamReader和StreamWriter两个类提供的方法来实现的。
12.5.1 StreamReader类 StreamReader类以一种特定的编码从字节流中读取字符,其常用的构造函数如下: StreamReader(Stream):为指定的流初始化StreamReader类的新实例。 StreamReader(String):为指定的文件名初始化StreamReader类的新实例。 StreamReader(Stream,Encoding):用指定的字符编码为指定的流初始化StreamReader类的一个新实例。 StreamReader(String,Encoding):用指定的字符编码,为指定的文件名初始化StreamReader类的一个新实例。 StreamReader类的常用的方法如表12.7所示。
使用Streamreader类读取数据的过程:首先通过File的OpenRead方法建立一个文件读取文件流,然后通过StreamReader类的方法将文件流中的数据读到C#编辑控件中(如文本框等)。
【例12.2】 设计一个窗体,在一个文本框中显示MyTest.txt文件中的数据(假设该文件已存在,其中有3行文字)。 Form2,设计界面 事件过程: private void button1_Click(object sender, EventArgs e) { string path = “H:\\MyTest.txt”; string mystr = ""; FileStream fs = File.OpenRead(path); StreamReader sr = new StreamReader(fs, Encoding.Default ); //指定打开文件 fs.Seek(0, SeekOrigin.Begin); //将文件流指针定位在开始位置 while (sr.Peek() > -1) mystr = mystr + sr.ReadLine() + "\r\n"; //\r\n表示回车换行 sr.Close(); fs.Close(); textBox1.Text = mystr; }
运行界面
12.5.2 StreamWriter类 StreamWriter类以一种特定的编码输出字符,其常用的构造函数如下: StreamWriter(Stream):用UTF-8编码及默认缓冲区大小,为指定的流初始化StreamWriter类的一个新实例。 StreamWriter(String):使用默认编码和缓冲区大小,为指定路径上的指定文件初始化StreamWriter类的新实例。 StreamWriter(Stream,Encoding):用指定的编码及默认缓冲区大小,为指定的流初始化StreamWriter类的新实例。 StreamWriter(string path,bool append):path表示要写入的完整文件路径。append表示确定是否将数据追加到文件。如果该文件存在,并且append为false,则该文件被改写;如果该文件存在,并且append为true,则数据被追加到该文件中。否则,将创建新文件。 StreamWriter类的常用的方法如表12.8所示。
使用StreamWriter类写入数据的过程:首先通过File类的OpenWrite建立一个写入文件流,然后通过StreamWriter的Write/WriteLine方法将C#编辑控件中(如文本框等)中的数据写入到该文件流中。
【例12.3】 设计一个窗体,用于将一个文本框中的数据写入到MyTest1.txt文件中,并在另一个文本框中显示这些数据。 Form3,设计界面 事件过程: using System; using System.IO; //引用System.IO命名空间,新增 using System.Text; using System.Windows.Forms; namespace Proj11_1 { public partial class Form3 : Form { string path = "H:\\MyTest1.txt"; //文件名path作为Form3类的字段 public Form3() { InitializeComponent(); }
private void Form3_Load(object sender, EventArgs e) { textBox1.Text = ""; textBox2.Text = ""; button1.Enabled = true; button2.Enabled = false; } private void button1_Click(object sender, EventArgs e) { if (File.Exists(path)) //存在该文件时删除之 File.Delete(path); else { FileStream fs = File.OpenWrite(path); StreamWriter sw = new StreamWriter(fs); sw.WriteLine(textBox1.Text); sw.Close(); fs.Close(); button2.Enabled = true;
private void button2_Click(object sender, EventArgs e) { string mystr = ""; FileStream fs = File.OpenRead(path); StreamReader sr = new StreamReader(fs); while (sr.Peek() > -1) mystr = mystr + sr.ReadLine() + "\r\n"; sr.Close(); fs.Close(); textBox2.Text = mystr; }
12.6 二进制文件操作 二进制文件操作是通过BinaryReader和BinaryWriter两个类提供的方法来实现的。 12.6 二进制文件操作 二进制文件操作是通过BinaryReader和BinaryWriter两个类提供的方法来实现的。 与文本文件的操作类似。
12.7 序列化和反序列化 序列化用于将对象的状态存储到文件中。 序列化用于将对象的状态存储到文件中。 在这一过程中,对象的公共字段和私有字段以及类的名称都被转换成字节流,然后写入数据流。在以后反序列化该对象时,创建原始对象的精确副本。 序列化 磁盘文件 对象 反序列化
12.7.1 序列化 序列化的一个类的最简单方式是使用Serializable属性标记,例如,以下声明了一个可序列的类Student: public class Student { private int no; //学号 private string name; //姓名 public int pno //属性 { get { return no; } set { no = value; } } public string pname //属性 get { return name; } set { name = value; }
以下代码说明了该类对象是如何被序列化到一个二进制文件中的: Student s = new Student(); s.pno=100; s.pname="John"; FileStream f = new FileStream(@"D:\C#程序\ch12\student.dat"",FileMode.Create); BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(f,s); f.Close(); 将对象s存储到文件中。
12.7.2 反序列化 反序列化将对象还原其以前的状况,首先创建用于读取的文件流和格式接口,然后用格式接口反序列化该对象。以下代码说明了这一过程: f = new FileStream(@"D:\C#程序\ch12\student.dat"", FileMode.Open); s = (Student)formatter.Deserialize(f); f.Close(); 其中@表示后面是一个路径字符串。需要特别注意的是,在反序列化一个对象时不调用构造函数。
━━本章完━━