Download presentation
Presentation is loading. Please wait.
Published byKlara Hansen Modified 6年之前
1
第5章 文件I/O操作 管理和读写文件信息的功能将使得应用程序的用途更多,利用C#语言编程能很容易实现这些操作。本章详细介绍了C#语言为我们提供的多个可以用于文件I/O操作的类及其使用方法。另外,流也是本章需要理解的一个重要概念,通过它对文件读写更加灵活方便。
2
5.1 用于文件操作的类 在计算机中,我们通过文件的形式把各种数据、文档、程序等软件资源永久性存储在各种媒质上(可移动磁盘、硬盘、CD等),并可以对它们进行读取、修改、复制、移动和删除等操作。文件是一种进行数据读写操作的有效方法,为了更方便地使用文件,操作系统中采用目录树的方法对文件进行管理,一个目录可以包含若干个文件和子目录,由此构成了一个由文件和目录组成的庞大的树状存储系统。在Windows系统中,我们习惯上把目录称为文件夹。
3
我们在编写一个较完整的应用程序时,肯定要涉及到对系统和用户的信息进行存储、读取、修改等操作,还常常需要设计自己的文件格式。因此,有效地实现文件操作,是一个良好的应用程序所必须具备的内容。C#语言为我们提供了多个可以用于文件操作的类,如图5-1所示,利用它们,可以很容易地实现对文件的存储管理、对文件的读写等各种操作。下面,我们给出几个可以常用于文件操作的类。 C#语言为我们提供了多个可以用于文件操作的类,利用它们,可以很容易地实现对文件的存储管理、对文件的读写等各种操作。下面,我们给出几个可以常用于文件操作的类。
4
Directory 类:提供多个对目录和子目录进行创建、移动和枚举的静态方法。 DirectoryInfo 类:提供多个对目录和子目录进行创建、移动和枚举的实例方法。 File 类:提供用于创建、复制、删除、移动和打开文件的静态方法,并协助创建FileStream类对象。 FileInfo类:提供用于创建、复制、删除、移动和打开文件的实例方法,并协助创建FileStream类对象。 FileStream类:支持通过其 Seek 方法随机访问文件。默认情况下,FileStream 以同步方式打开文件,但它也支持异步操作。 FileSystemInfo类:是 FileInfo类 和 DirectoryInfo类 的抽象基类。 Path类:提供以跨平台的方式处理目录字符串的方法和属性。
5
如果在程序中使用这些类,需要引入这些类所在的名称空间,即在程序源文件的最前面加入语句 using System
如果在程序中使用这些类,需要引入这些类所在的名称空间,即在程序源文件的最前面加入语句 using System.IO; ,否者,系统将无法识别这些类。 5.2 目录和路径操作 5.2.1 Directory类 Directory 类既可以用来复制、移动、重命名、创建和删除目录,也可用来获取和设置与目录的创建、访问及写入操作相关的时间信息。Directory类是无状态的,它的成员函数全部都是静态的,每次执行前都要进行安全检查。Directory 类主要成员函数如表5-1所示:
6
表5-1 Directory 类的主要成员函数 CreateDirectory 创建目录和子目录 Delete 删除目录及其内容。
Exists 确定指定目录是否存在。 GetCreationTime 获取目录的创建日期和时间。 GetCurrentDirectory 获取应用程序的当前工作目录。 GetDirectories 获取指定目录中子目录的名称。 GetFiles 返回指定目录中的文件的名称。 GetLastAccessTime 返回上次访问指定目录的日期和时间。 GetLastWriteTime 返回上次写入指定目录的日期和时间。
7
- GetParent 返回指定路径的父目录,包括绝对路径和相对路径。 Move 将目录及其内容移到新位置。 SetCreationTime
设置指定的目录被创建的日期和时间。 SetCurrentDirectory 将应用程序的当前工作目录设置为指定的目录。 SetLastAccessTime 设置上次访问指定目录的日期和时间。 SetLastWriteTime 设置上次写入目录的日期和时间。
8
案例:练习使用Directory 类 目标:掌握Directory 类及其部分主要方法的使用技巧 步骤:
1、启动VS.NET,新建一个控制台应用程序,名称填写为“DirectoryTest”,位置设置为“c:\CSharpSamples\chp5”。 2、在代码设计窗口中编辑Class1.cs。其中的代码编写如下: using System; using System.IO; namespace DirectoryTest { class DirectoryTest { public static void Main() {
9
// 指定您想要操作的目录. string source = @"c:\SourceDir";
// 指定您想要操作的目录 string source string target try { // 判断目录是否存在 if (!Directory.Exists(source)) { // 如果源目录不存在则创建它 Directory.CreateDirectory(source); } if (Directory.Exists(target)) {// 如果目标目录存在则删除它 Directory.Delete(target, true);
10
// 移动目录,就是把源目录移动到目标目录,更直接地说,就是把由source指定的源目录内所有文件和子目录都移动到由target指定的目标目录中去,同时删除了源目录。
Directory.Move(source, target); //返回目标目录被创建、最后被访问、最后被修改的时间 Console.WriteLine("目录 {0} 被移动到目录 {1} 。", source,target); Console.WriteLine("目录 {0} 被创建的时间是 :{1}", target,Directory.GetCreationTime(target));
11
Console. WriteLine("目录 {0} 最后被访问的时间是 :{1}", target,Directory
Console.WriteLine("目录 {0} 最后被访问的时间是 :{1}", target,Directory.GetLastAccessTime(target)); Console.WriteLine("目录 {0} 最后被修改的时间是 :{1}", target,Directory.GetLastWriteTime(target)); } catch (Exception e) {Console.WriteLine("操作失败: {0}", e.ToString()); finally {}
12
3、按Ctrl + F5编译并运行该程序,效果如图5-2所示。
图 5-2 程序运行结果 程序运行结束后,源目录c:\SourceDir中内容将被移动到目标目录c:\TargetDir中,请注意观察程序运行前后系统磁盘目录的变化情况。
13
5.2.2 DirectoryInfo类 DirectoryInfo类与Directory类具有相同的功能和用途,它们的成员函数也大致相同。但DirectoryInfo类是有状态的,它的成员函数都不是静态的,使用时必需先实例化成一个对象,然后通过对象进行调用。如果使用同一个对象执行多个操作时,使用DirectoryInfo就比较有效,因为对该对象所关联文件的安全检查仅在对象被构造时执行一次,其后无论该对象调用了多少方法,都不需要再进行安全检查了。DirectoryInfo 类主要属性和成员函数如表5-2所示:
14
表5-2 DirectoryInfo 类的主要属性和成员函数
描述 Attributes 目录属性,枚举值,0x01表示只读,0x02表示隐藏。 Name 当前目录名。 FullName 当前目录的全名。 Parent 上一级父目录名。 Root 所在根目录名。 Exists 目录是否存在。
15
- CreationTime 目录被创建时间。 LastAccessTime 最后一次访问目录的时间。 成员函数 描述
DirectoryInfo 构造函数,其中的参数表示目录所在的路径。 Create 创建目录。 Delete 删除目录及其内容。
16
案例:练习使用DirectoryInfo 类 目标:掌握使用DirectoryInfo 类进行目录管理的使用技巧 步骤:
1、启动VS.NET,新建一个控制台应用程序,名称填写为“DirectoryInfoTest”,位置设置为“c:\CSharpSamples\chp5”。 2、在代码设计窗口中编辑Class1.cs。其中的代码编写如下: using System; using System.IO; namespace DirectoryInfoTest
17
{ class DirectoryInfoTest { public static void Main() {
//实例化DirectoryInfo类对象d,并把它和目录"c:\temp"关联起来 DirectoryInfo d = new DirectoryInfo("c:\\temp"); //判断目录是否存在 if (!d.Exists) { //如果目录不存在则创建它 d.Create();
18
Console. WriteLine("创建了目录: {0}",d. FullName);. }
Console.WriteLine("创建了目录: {0}",d.FullName); } //声明两个DirectoryInfo类对象d1和d2 DirectoryInfo d1; DirectoryInfo d2; try { //利用d创建子目录,并把d1和新创建的目录"c:\temp\子目录1"关联起来 d1 = d.CreateSubdirectory("子目录1");
19
Console.WriteLine("创建了目录: {0}",d1.FullName); } catch(IOException e) { //创建失败,给出提示信息,结束程序 Console.WriteLine("子目录1创建失败!"); return; } try { //利用d1创建子目录,并把d2和新创建的目录"c:\temp\子目录1\子目录2"关联起来
20
d2 = d1. CreateSubdirectory("子目录2");. Console
d2 = d1.CreateSubdirectory("子目录2"); Console.WriteLine("创建了目录: {0}",d2.FullName); } catch(IOException e) { Console.WriteLine("子目录2创建失败!"); return; } try { //利用d创建子目录,并把d2和新创建的目录"c:\temp\子目录1\子目录3"关联起来
21
//DirectoryInfo类对象数组,用于存储某目录下的所有子目录 DirectoryInfo [] subdir;
d2 = d.CreateSubdirectory("子目录1\\子目录3"); Console.WriteLine("创建了目录: {0}",d2.FullName); } catch(IOException e) { Console.WriteLine("子目录3创建失败!"); return; } //DirectoryInfo类对象数组,用于存储某目录下的所有子目录 DirectoryInfo [] subdir;
22
//依次处理"c:\temp"目录中的所有子目录 foreach(DirectoryInfo dir in subdir)
try {//返回指定目录"c:\temp"中的所有子目录,并把它们存放在subdir数组中 subdir = d.GetDirectories(); } catch(DirectoryNotFoundException e) { Console.WriteLine("目录不存在错误"); return; } //依次处理"c:\temp"目录中的所有子目录 foreach(DirectoryInfo dir in subdir)
23
{ //删除目录,参数为true时,表示无条件直接删除该目录及其中包含的所有子目录和文件. dir. Delete(true);
{ //删除目录,参数为true时,表示无条件直接删除该目录及其中包含的所有子目录和文件 dir.Delete(true); Console.WriteLine("删除了目录: {0} (包含其中所有文件和子目录)",dir.FullName); } //删除目录,参数为false时,如果目录非空,会产生运行期错误 d.Delete(false); Console.WriteLine(“删除了目录: {0}”,d.FullName); } }
24
3、按Ctrl + F5编译并运行该程序,效果如图5-3所示。
图 5-3 程序运行结果
25
5.2.3 Path类
26
Path类用于以跨平台的方式处理目录字符串,它包含一些静态的属性和方法,可以很容易地对路径名执行操作。使用Path类要比手工处理各个符号容易得多,因为Path类在处理不同操作系统上的路径名时,会使用不同的格式。最简单的情况,Path类处理Unix路径时,是以/(并不是\)用作路径名中的分隔符,而处理Windows 和 Macintosh 路径时,是以\ (并不是/)用作路径名中的分隔符的。Path 类成员函数如表5-3所示: 表5-3 Path 类的主要成员函数列表
27
- 成员函数 描述 GetFileNameWithoutExtension 返回不具有扩展名的指定路径字符串的文件名。
GetExtension 返回指定的路径字符串的扩展名。 GetFileName 返回指定路径字符串的文件名和扩展名。 GetDirectoryName 返回指定路径字符串的目录信息。 GetFullPath 返回指定路径字符串的绝对路径。 HasExtension 确定路径是否包括文件扩展名。 ChangeExtension 更改路径字符串的扩展名。 Combine 合并两个路径字符串。
28
案例:练习使用Path 类 目标:掌握使用Path 类处理目录字符串的使用技巧 步骤:
1、启动VS.NET,新建一个控制台应用程序,名称填写为“PathTest”,位置设置为“c:\CSharpSamples\chp5”。 2、在代码设计窗口中编辑Class1.cs。其中的代码编写如下: using System; using System.IO; namespace PathTest {
29
class PathTest { public static void Main() {
//需要处理的目录字符串path1、path2、path3和path4 string path1 string path2 string path3 //判断是否具有扩展名 if (Path.HasExtension(path1))
30
{. Console. WriteLine("路径 {0} 中含有文件扩展名。\n", path1);
{ Console.WriteLine("路径 {0} 中含有文件扩展名。\n", path1); //分别返回该路经中包含的文件名、文件扩展名、文件全名和目录名 Console.WriteLine(" 其文件名是:{0}", Path.GetFileNameWithoutExtension(path1)); Console.WriteLine(" 其文件扩展名是:{0}", Path.GetExtension(path1)); Console.WriteLine(" 其文件全名是:{0}", Path.GetFileName(path1)); Console.WriteLine(" 其目录名是:{0}",
31
Path.GetDirectoryName(path1)); //更改文件的扩展名为".doc" string result=Path.ChangeExtension(path1,".doc"); Console.WriteLine(" 更改后的文件扩展名是:{0}", Path.GetExtension(result)); } //合并两个路径字符串。当第二个路径中不含扩展名时,第二个路径被当作子目录处理。 Console.WriteLine("\n路径{0}和路径{1}合并后,新的路径为{2}。", path2,path3,Path.Combine(path2,path3));
32
//合并两个路径字符串。当第二个路径中含有扩展名时,第二个路径被当作文件处理。. Console
//合并两个路径字符串。当第二个路径中含有扩展名时,第二个路径被当作文件处理。 Console.WriteLine("路径{0}和路径{1}合并后,新的路径为{2}。", path2,path4,Path.Combine(path2,path4)); } } } 3、按Ctrl + F5编译并运行该程序
33
5.3 创建文件 对文件进行读写,首先要创建文件,下面介绍几个与文件密切相关的类。 5.3.1 File类
File 类既可以用来创建、复制、删除、移动和打开文件,也可用来获取和设置文件属性或有关文件创建、访问及写入操作的时间信息。File类是无状态的,它的成员函数全部都是静态的,每次执行前都要进行安全检查。
34
案例:练习使用File 类 目标:掌握File 类及其主要成员函数的使用技巧 步骤:
1、启动VS.NET,新建一个控制台应用程序,名称填写为“FileTest”,位置设置为“c:\CSharpSamples\chp5”。 2、在代码设计窗口中编辑Class1.cs。其中的代码编写如下: using System; using System.IO; namespace FileTest
35
{ public class FileTest { public static void Main()
{ string path //判断目录是否存在 if (!Directory.Exists(Path.GetDirectoryName(path))) { // 如果目录不存在则创建它 Directory.CreateDirectory(Path.GetDirectoryName(path)); }
36
//判断文件是否存在 if (File.Exists(path)) { //如果文件存在则删除它 File.Delete(path); }
//创建文件 File.Create(path); Console.WriteLine("****************读取文件属性 *********************"); //读取文件的各种属性
37
Console. WriteLine("文件名: {0}",path);. Console
Console.WriteLine("文件名: {0}",path); Console.WriteLine("文件被创建时间: {0}", File.GetCreationTime(path)); Console.WriteLine("文件最后一次被访问时间: {0}", File.GetLastAccessTime(path)); Console.WriteLine("文件最后一次被修改时间: {0}", File.GetLastWriteTime(path)); Console.WriteLine("\n****************设置文件属性 *********************");
38
Console.WriteLine("文件 {0} 被设置为隐藏文件。", path); }
//把文件设置为隐藏文件 File.SetAttributes(path, File.GetAttributes(path) | FileAttributes.Hidden); Console.WriteLine("文件 {0} 被设置为隐藏文件。", path); } 3、按Ctrl + F5编译并运行该程序
39
5.3.2 FileInfo类 FileInfo类与File类具有相同的功能和用途,它们的成员函数也大致相同。但FileInfo类是有状态的,它的成员函数都不是静态的,使用时必需先实例化成一个对象,然后通过对象进行调用。如果使用同一个对象执行多个操作时,使用FileInfo就比较有效,因为对该对象所关联文件的安全检查仅在对象被构造时执行一次,其后无论该对象调用了多少方法,都不需要再进行安全检查了。
40
namespace FileInfoTest { public class CopyFile
案例:文件的复制 目标:掌握使用FileInfo 类进行文件操作的使用技巧 步骤: 1、启动VS.NET,新建一个控制台应用程序,名称填写为“FileInfoTest”,位置设置为“c:\CSharpSamples\chp5”。 2、在代码设计窗口中编辑Class1.cs。其中的代码编写如下: using System; using System.IO; namespace FileInfoTest { public class CopyFile
41
{ public static void Main(String[] args) { //要被复制的源文件名
string sourcefilename; //被复制到的目标文件名 string targetfilename; //判断输入的命令格式是否正确 if (args.Length<2) { Console.WriteLine("命令的正确格式是: 命令名 源文件名 目标文件名 。");
42
return; } else { sourcefilename = args[0]; targetfilename = args[1]; }
try { //创建FileInfo类的对象fi,用来和源文件相关联 FileInfo fi = new FileInfo(sourcefilename);
43
//进行文件的复制,如果第二个参数为false时,目标文件如果存在则会产生运行期错误,如果第二个参数为true时,目标文件如果存在则覆盖,不会产生错误。
fi.CopyTo(targetfilename,false); } catch(System.IO.FileNotFoundException) { Console.WriteLine("源文件 {0} 不存在",sourcefilename); return; catch(System.IO.IOException) { Console.WriteLine("目标文件 {0} 已经存在",targetfilename);
44
3、按Ctrl + F5编译并运行该程序,效果如图5-6所示。
return; } catch(Exception) { Console.WriteLine("文件复制失败!"); return; } Console.WriteLine("文件复制成功! "); } } } 3、按Ctrl + F5编译并运行该程序,效果如图5-6所示。
45
图 5-6 程序运行结果 这个程序用来完成文件的复制,正确的使用格式是:“命令名 源文件名 目标文件名”,比如当输入为“CopyFile c:\s.txt d:\d.doc”,则该程序会把源文件c:\s.txt复制到目标文件d:\d.doc中去。
46
5.3.3 FileStream类
47
FileStream 类用来对文件系统上的文件进行读取、写入、打开和关闭等操作。由于FileStream 类能够对输入输出进行缓冲,因而处理性能比较高。FileStream类的成员函数都是非静态的,需要通过FileStream类的实例对象对文件中的数据进行读写。要构造FileStream实例,一般需要四条信息: 1.要访问的文件。 2.表示如何打开文件的模式。例如,创建一个新文件或打开一个现有的文件。如果打开一个现有文件,写入操作是应改写文件原来的内容,还是添加到文件的末尾? 3.表示如何访问文件的访问方式。是只读、只写,还是读写? 4.共享访问。是独占访问文件,还是允许其它流同时访问文件?如果允许其它流同时访问文件,则这些流是只读、只写,还是读写文件?
48
第一条信息通常用一个包含文件完整路径名的字符串来表示。其余三条信息分别由三个枚举常量FileMode、FileAccess和FileShare来表示
注意,对于FileMode,如果要求的模式与文件的现有状态不一致,就会抛出一个异常。如果文件不存在,Append、Open和Truncate会抛出一个异常;如果文件存在,CreateNew会抛出一个异常;Create和OpenOrCreate可以处理这两种情况,但Create会删除现有的文件,创建一个新的空文件。
49
FileStream有许多构造函数,其中三个最简单的构造函数如下所示: FileStream fs1=new FileStream FileStream fs2=new ", FileMode.Create, FileAccess.Write); FileStream fs3=new ", 从上面的代码可以看出,构造函数有很多个重载方法,其中FileAccess.ReadWrite和FileShare.Read的是构造函数第三和第四个参数的默认缺省值。
50
此外,也可以从FileInfo实例中创建一个文件流。 FileInfo fi4 = new "); FileStream fs4 = fi4.OpenRead(); FileInfo fi5 = new "); FileStream fs5 = fi5.OpenWrite(); FileInfo fi6 = new "); FileStream fs6 = fi6.Create(); FileInfo fi7 = new "); FileStream fs7 = fi7.Open(FileMode.Append, FileAccess.Read, FileShare.None);
51
上面介绍的三个有关文件的类File、FileInfo和FileStream都可以用来创建文件,大致总结一下,创建文件的方法主要有以下几种:
FileInfo.OpenRead()提供的流只能读取现有的文件,而FileInfo.OpenWrite()可以进行读写访问。FileInfo.Open()允许显式指定模式、访问方式和文件共享参数。 5.3.4 创建文件的几种方法 上面介绍的三个有关文件的类File、FileInfo和FileStream都可以用来创建文件,大致总结一下,创建文件的方法主要有以下几种: 1.使用File类创建文件: string path
52
// 使用成员函数CreateText创建一个新的文本文件进行读写,其参数是一个表示新建文件路径的字符串,返回值是一个StreamWriter类的对象。StreamWriter类主要用于文本文件的写入,详细使用方法参见5.4.2 使用StreamReader和StreamWriter类读写文本文件。 StreamWriter sw1 = File.CreateText(path)); // 向path指定的文件追加文本。如果文件存在,则在文件尾部追加内容,否则,创建该文件。 StreamWriter sw2 = File.AppendText(path)); // 创建一个新的文件进行读写,FileStream 类主要用于文件的读写,详细使用方法参见使用5.4.1 FileStream类读写文件。
53
FileStream fs = File.Create(path);
使用FileInfo类创建文件: // 实例化FileInfo类的对象fi FileInfo fi = new // 创建一个新的文本文件进行读写。 StreamWriter sw1 = fi.CreateText() ; // 向实例对象fi表示的文件追加文本。如果文件存在,则在文件尾部追加内容,否则,创建该文件。
54
StreamWriter sw2 = fi.CreateText(); // 创建一个新的文件进行读写。 FileStream fs = fi.Create();
FileStream fs1=new FileStream FileStream fs2=new ", FileMode.Create, FileAccess.Write); FileStream fs3=new ", FileMode.Create, FileAccess.Read, FileShare.None);
55
5.4 读写文件 读写文件是对文件最常用的操作。读写文件时,通常要通过流(Stream)来完成。流指的是信息流,一个流是字节的源或目的,流是有次序的。例如,一个需要键盘输入的程序可以用流来完成信息的输入。 有两种基本的流:输入流和输出流。你可以从输入流读,但你不能对它写。要从输入流读取字节,必须有一个与这个流相关联的字符源,比如文件、内存或键盘等。同理,你可以向输出流写,但你不能对它读。要向输出流写入字节,必须有一个与这个流相关联的字符源,比如文件、内存或显示器等。
56
由此可见,流可以用于向文件发送信息和接收来自文件的信息。读写文件时,需要按一定的步骤进行。首先需要打开文件。如果是创建新文件,则在创建该文件的同时,应该打开它。文件打开后,需要使用流来将信息加入到文件中或从文件中取出信息。创建流时,需要指明信息的流动方向。将流与文件关联起来后,便可以开始读写数据了。如果是读取文件中的信息,则可能需要检查是否到了文件的末尾。读写完信息后,需要关闭文件。 读取文件的基本步骤如下: 打开或创建文件; 建立从文件中取出信息或向文件写入信息的流; 将信息加入到文件中或从文件中读取信息; 关闭流和文件。
57
5.4.1 使用FileStream类读写文件 FileStream类在前面的章节中已经进行了介绍,并详细介绍了它的各种构造函数。从类的名字可以看出,FileStream类本身就是一个用来进行文件读写的流。FileStream类中提供了许多可以进行文件读写的实例方法。 ReadByte()是读取数据的最简单的方式,它从流中读取一个字节,并把这个字节转换为一个0到255之间的整数。如果到达该流的末尾,就返回 –1 。 int nextByte = fs.ReadByte(); // fs为FileStream类的一个实例对象
58
如果想要一次读取多个字节,可以调用Read()方法,它可以把特定数量的字节读入到一个数组中。Read()方法返回实际读取的字节数。如果返回值是0,就表示已经到达了流的尾端。
// 一次读入100个字节 int nBytes = 100; byte nBytesRead [nBytes]; int nBytesRead = fs.Read(nBytesRead, 0,nBytes); Read()的第一个参数是一个byte类型的数组;第二个参数是一个偏移值,使用它可以要求Read读取的数据从数组的某个元素开始,而不是从第一个元素开始;第三个参数是最多读取的字节数。
59
如果要给文件写入数据,可以使用方法WriteByte()和Write()。WriteByte()方法把一个字节写入流:
byte nextByte = 100; fs. WriteByte(nextByte); 如果想要一次写入多个字节,可以调用Write()方法,它可以把一个数组中特定数量的字节写入流。 //一次写入100个字节 int nBytes=100; byte [] ByteArray = new byte[nBytes];
60
for (int i = 0 ; i <100 ; i++) { ByteArray[i] = i; //设置要输出的多个字节 } fs.Write(ByteArray, 0, nBytes);
与Read()方法一样,Write ()方法的第一个参数是一个byte类型的数组,用于存储准备写入的字节数据;第二个参数是一个偏移值,使用它可以要求Write写入的数据从数组的某个元素开始,而不是从第一个元素开始;第三个参数是最多写入的字节数。 WriteByte()和Write()都没有返回值。
61
使用流完成所有写操作之后,应清除该流的所有缓冲区,并把缓冲区中的数据写入到文件中去,避免数据遗失。这个操作使用Flush()方法完成。 fs
使用流完成所有写操作之后,应清除该流的所有缓冲区,并把缓冲区中的数据写入到文件中去,避免数据遗失。这个操作使用Flush()方法完成。 fs. Flush (); 使用完一个流后,就应关闭它,关闭流使用Close()方法。 fs.Close(); 关闭流会释放与它相关的资源,允许其它应用程序为同一个文件设置流。在打开和关闭流之间,可以读写其中的数据。 案例:练习使用FileStream类读写文件 目标:掌握使用FileStream类读写文件的使用技巧
62
步骤: 1、启动VS.NET,新建一个控制台应用程序,名称填写为“FileStreamTest”,位置设置为“c:\CSharpSamples\chp5”。 2、在代码设计窗口中编辑Class1.cs。其中的代码编写如下: using System; using System.IO; namespace FileStreamTest { public class FileStreamTest { public static void Main(String[] args) {
63
//新建一个文件,并向文件中写入数据. FileInfo fi = new FileInfo("c:\\csc. dat");
//新建一个文件,并向文件中写入数据 FileInfo fi = new FileInfo("c:\\csc.dat"); FileStream fs = fi.Create(); int nBytes = 100; byte [] wByteArray = new byte[nBytes]; for (int i = 0 ; i <100 ; i++) { wByteArray[i] = (byte)(i+1); //设置要写入文件的多个字节 } //把多个字节直接一次写入文件 fs.Write(wByteArray, 0, nBytes);
64
//刷新缓冲区,保证把数据写入文件 fs.Flush(); //关闭文件流 fs.Close(); //打开一个文件,并从文件中读出数据
fs = fi.OpenRead(); byte[] rByteArray=new byte[nBytes]; //把多个字节的数据从文件读到字节数组中,返回读入数据的总字节数 int nBytesRead=fs.Read(rByteArray, 0, nBytes); //分行显示读入的数据 for (int i = 0 ; i <100 ; i++)
65
{ if ((i+1)%5. =0). {. Console. Write(rByteArray[i]+"\t");. }. else. {
{ if ((i+1)%5!=0) { Console.Write(rByteArray[i]+"\t"); } else { Console.Write(rByteArray[i]+"\n"); } } Console.WriteLine("\n共有 {0} 个字节的数据从文件中被读出。", nBytesRead.ToString());
66
fs.Close(); } } } 3、按Ctrl + F5编译并运行该程序
67
5.4.2 使用StreamReader和StreamWriter类读写文本文件
理论上,可以使用FilStream类读取和显示文本文件。但通常使用StreamReader和StreamWriter类来更方便地读取它们。这是因为这两个类工作的级别比较高,特别适合于读取文本。它们的成员函数可以一次读写一行文本StreamReader.ReadLine()和StreamWriter. WriteLine()。在读取文件时,流会自动确定下一个回车符的位置,并在该处停止读取,在写入文件时,流会自动把回车符和换行符添加到文本的末尾。
68
另外,使用StreamReader和StreamWriter类,就不需要担心文件中使用的编码方式了。编码方式是指文件中的文本用什么格式存储。可能的编码方式是ASCII(一个字节表示一个字符)或者基于Unicode的格式,UNICODE、UTF7和UTF8。Windows 9x系统上的文本文件总是ASCII格式,因为Windows 9x系统不支持Unicode,但Windows NT-2000-XP都支持Unicode,所以文本文件理论上可以包含UNICODE、UTF7或UTF8数据,而不包含ASCII数据。 其约定是:如果文件是ASCII格式,就只包含文本。如果是Unicode格式,就用文件的前两个或三个字节来表示,这几个字节可以设置为表示格式的值的特定组合。这些字节称为字节码标记。
69
在使用标准Windows应用程序打开一个文件时,例如Notepad或WordPad,不需要考虑这个问题,因为这些应用程序都支持不同的编码方法,会自动正确地读取文件。StreamReader类也是这样,它可以正确读取任何格式的文件,而StreamWriter类可以使用任何一种编码技术格式化它要写入的文本。 1.StreamReader类 StreamReader用于读取文本文件。StreamReader类有很多种构造函数用来实例化对象。最简单的构造函数是使用StreamReader来直接连接文件。
70
StreamReader sr = new StreamReader(@"C:\temp\ReadMe
StreamReader sr = new StreamReader sr = new Encoding.ASCII); 第二个构造函数的第二个参数是告诉StreamReader该文件使用哪种编码方法。类System.Text.Encoding的几个属性,被用来指定编码方法。编码方法取值及含义如表5-8所示: 属性 含义 Encoding.ASCII 获取 ASCII(7 位)字符集的编码。
71
- Encoding.Unicode 获取Unicode 格式的编码。 Encoding.UTF7 获取 UTF-7 格式的编码。
72
另外,构造函数也可以不提供要读取的文件名,而是提供另一个流,我们可以把StreamReader关联到FileStream上。其优点是可以显式指定是否创建文件和共享许可,如果直接把StreamReader关联到文件上,就不会有这样的优点了。 FileStream fs = new " C:\temp\ReadMe.txt ", FileMode.Open, FileAccess.Read, FileShare.None]; StreamReader sr = new StreamReade(fs); 此外,通过File和FileInfo类的方法也可以得到StreamReader类的对象。 string path ";
73
StreamReader sr = File. OpenText (path); FileInfo fl = new FileInfo "); StreamReader sr = fl.OpenText(); StreamReader类最常用的成员函数是ReadLine(),该方法一次读取一行文本,但返回的字符串中不包括标记该行结束的回车换行符。 string nextLine = sr.ReadLine(); 与FileStream一样,应在使用后关闭StreamReader。如果没有这样做,就会致使文件一直锁定,不能被其它的过程使用。 sr.Close();
74
2.StreamWriter StreamWriter用于写入文本文件。StreamWriter类的工作方式与StreamReader类似,但StreamWriter只能用于写入文件(或另一个流)。构造StreamWriter的方法包括: StreamWriter sw=new C:\temp\ReadMe.txt "); StrearnWriter sw=new ",true,Encoding.ASCII); 第二个构造函数的第二个参数为true或false,表示文件是否应以追加的方式打开。第三个参数表示写入文件时的编码方法,其取值和含义与ReaderStream类中相同,请参见表5-8 编码方法取值及含义。
75
另外,也可以把StreamWriter关联到一个FileStream上,以获得打开文件的更多控制选项。
FileStream fs=new ", FileMode.CreateNew, FileAccess.Write, FileShare. Read); StreamWriter sw = new StreamWriter(fs); 此外,通过File和FileInfo类的方法也可以得到StreamWriter类的对象。 string path "; StreamWriter sw = File. CreateText (path); FileInfo fl = new FileInfo "); StreamWriter sw = fl. CreateText ();
76
案例:练习使用StreamReader和StreamWriter类读写文本文件
StreamWriter类最常用的成员函数是WriteLine(),该方法一次写入一行文本,并在其后面加上一个回车换行符。 sw. WriteLine (); 与其他流类一样,应在使用后关闭StreamReader。如果没有这样做,就会致使文件一直锁定,不能被其它的过程使用。 sw.Close(); 案例:练习使用StreamReader和StreamWriter类读写文本文件 目标:掌握使用StreamReader和StreamWriter类读写文本文件的使用技巧 步骤:
77
1、启动VS.NET,新建一个控制台应用程序,名称填写为“StreamTest”,位置设置为“c:\CSharpSamples\chp5”。 2、在代码设计窗口中编辑Class1.cs。其中的代码编写如下: using System; using System.IO; namespace StreamTest { public class StreamTest { public static void Main(String[] args) { string path
78
try { if (File.Exists(path)) { File.Delete(path); }
//向文件中写入文本 using (StreamWriter sw = new StreamWriter(path)) { sw.WriteLine(" 静夜思 "); sw.WriteLine("窗前明月光,"); sw.WriteLine("疑似地上霜。"); sw.WriteLine("举头望明月,"); sw.WriteLine("低头思故乡。"); }
79
//从文件中读取文本. using (StreamReader sr = new StreamReader(path)). {
//从文件中读取文本 using (StreamReader sr = new StreamReader(path)) { //成员函数Peek()用来返回下一个可用的字符,如果没有更多的可用字符,则返回 -1 while (sr.Peek() >= 0) { //每次读取一行文本 Console.WriteLine(sr.ReadLine()); }
80
catch (Exception e). {. Console. WriteLine("处理操作失败: {0}", e
catch (Exception e) { Console.WriteLine("处理操作失败: {0}", e.ToString()); } } } }
81
3、按Ctrl + F5编译并运行该程序,效果如图5-8所示。
图5-8
Similar presentations