GPS 平台, 网站建设, 软件开发, 系统运维, 找森大网络科技!
http://cnsendnet.taobao.com/
来自森大科技官方博客
- http://www.cnsendblog.com/index.php/?p=459
- C# 高级编程: 读写文本文件
理论上, 可以使用 FileStream 类读取和显示文本文件. 前面已经介绍了这个类. 上面显示 NewFile.txt 文件的格式不太容易理解, 但这并不是 FileStream 类的问题 -- 而在于我们在文本框中显示结果所使用的方式.
如果知道某个文件包含文本, 通常就可以使用 StreamReader 和 StreamWriter 类更方便地读写它们. 这是因为这些类工作的级别比较高, 特别适合于读写文本. 它们执行的方法可以根据流的内容, 自动检测出停止读取文本较方便的位置, 特别是:
●这些类执行的方法可以一次读写一行文本(StreamReader.ReadLine() 和 StreamWriter.WriteLine()). 在读取文件时, 流会自动确定下一个回车符的位置, 并在该处停止读取. 在写入文件时, 流会自动把回车符和换行符添加到文本的末尾.
●使用 StreamReader 和 StreamWriter 类, 就不需要担心文件中使用的编码方式 (文本格式) 了. 可能的编码方式是 ASCII(一个字节表示一个字符)或者基于 Unicode 的格式, UNICODE,UTF7 和 UTF8.Windows 9x 系统上的文本文件总是 ASCII 格式, 因为 Windows 9x 系统不支持 Unicode, 但 Windows NT,2000,XP 和 2003 都支持 Unicode, 所以文本文件除了包含 ASCII 数据之外, 理论上可以包含 Unicode,UTF7 或 UTF8 数据. 其约定是: 如果文件是 ASCII 格式, 就只包含文本. 如果是 Unicode 格式, 就用文件的前两个或三个字节来表示, 这几个字节可以设置为表示文件中格式的值的特定组合.
这些字节称为字节码标记. 在使用标准 Windows 应用程序打开一个文件时, 例如 Notepad 或 WordPad, 不需要考虑这个问题, 因为这些应用程序都支持不同的编码方法, 会自动正确地读取文件. StreamReader 类也是这样, 它可以正确读取任何格式的文件, 而 StreamWriter 类可以使用任何一种编码技术格式化它要写入的文本. 另一方面, 如果要使用 FileStream 类读取和显示文本文件, 就不必自己处理这个过程了.
1. StreamReader 类
StreamReader 用于读取文本文件. 用某些方式构造一个 StreamReader 要比构造一个 FileStream 实例更简单, 因为使用 StreamReader 时不需要 FileStream 的一些选项. 特别是不需要模式和访问类型, 因为 StreamReader 只能执行读取操作. 除此以外, 没有指定共享许可的直接选项, 但 StreamReader 有两个新选项:
●需要指定不同的编码方法所执行的不同操作. 可以构造一个 StreamReader 检查文件开头的字节码标记, 确定编码方法, 或者告诉 StreamReader 该文件使用某个编码方法.
●不提供要读取的文件名, 而为另一个流提供引用.
最后一个选项需要解释一下, 因为它涉及到把读写数据的模型建立在流概念上的另一个优点. StreamReader 工作在相对比较高的级别上, 如果有另一个流在读取其他源的数据, 就要使用由 StreamReader 提供的工具来处理这个流, 因为这个流包含文本, 此时 StreamReader 就非常有用了. 可以把这个流的输出传送到 StreamReader 上, 这样, StreamReader 就可以读取和处理任何数据源 (不仅仅是文件) 中的数据了. 前面在讨论 BinaryReader 类时也讨论了这种情况. 但在本书中, 只使用 StreamReader 来直接连接文件.
其结果是 StreamReader 有非常多的构造函数. 而且, 还有两个返回 StreamReader 引用的 FileInfo 方法: OpenText() 和 CreateText(). 下面仅说明其中一些构造函数.
最简单的构造函数只带一个文件名参数. StreamReader 会检查字节码标记, 确定编码方法:
StreamReader sr = new StreamReader(@"C:"My Documents"ReadMe.txt");
另外, 如果指定 UTF8 编码方法:
- StreamReader sr = new StreamReader(@"C:"My Documents"ReadMe.txt",
- Encoding.UTF8);
使用类 System.Text.Encoding 上的几个属性之一, 就可以指定编码方法. 这个类是一个抽象基类, 可以根据这个类定义许多类, 其方法可执行实际的文本编码. 每个属性都返回相应类的一个实例, 可以使用的属性包括:
●ASCII
●Unicode
●UTF7
●UTF8
●BigEndianUnicode
下面的示例解释了如何把 StreamReader 关联到 FileStream 上. 其优点是可以显式指定是否创建文件和共享许可, 如果直接把 StreamReader 关联到文件上, 就不能这么做:
- FileStream fs = new FileStream(@"C:"My Documents"ReadMe.txt",
- FileMode.Open, FileAccess.Read, FileShare.None);
- StreamReader sr = new StreamReader(fs);
对于本例, 指定 StreamReader 查找字节码标记, 以确定使用了什么编码方法, 以后的示例也是这样, 从一个 FileInfo 实例中获得 StreamReader:
- FileInfo myFile = new FileInfo(@"C:"My Documents"ReadMe.txt");
- StreamReader sr = myFile.OpenText();
与 FileStream 一样, 应在使用后关闭 StreamReader. 如果没有这样做, 就会致使文件一直锁定, 因此不能执行其他过程(除非使用 FileStream 构造 StreamReader 和特定的 FileShare. ShareReadWrite):
sr.Close();
介绍完实例化 StreamReader 后, 就可以用该实例作一些工作了. 与 FileStream 一样, 我们仅指出可以用于读取数据的许多方式, 您应在 SDK 文档说明书中查阅其他不太常用的 StreamReader 方法.
所使用的最简单的方式是 ReadLine(), 该方法一次读取一行, 但返回的字符串中不包括标记该行结束的回车换行符:
string nextLine = sr.ReadLine();
另外, 还可以在一个字符串中提取文件的所有剩余内容(严格地说, 是流的全部剩余内容):
string restOfStream = sr.ReadToEnd();
可以只读取一个字符:
int nextChar = sr.Read();
Read()的重载方法可以把返回的字符转换为一个整数, 如果到达流的尾端, 就返回 - 1.
最后, 可以用一个偏移值, 把给定个数的字符读到数组中:
- // to read 100 characters in.
- int nChars = 100;
- char [] charArray = new char[nChars];
- int nCharsRead = sr.Read(charArray, 0, nChars);
如果要求读取的字符数多于文件中剩余的字符数, nCharsRead 应小于 nChars .
2. StreamWriter 类
StreamWriter 类的工作方式与 StreamReader 的类似, 但 StreamWriter 只能用于写入文件(或另一个流). 构造 StreamWriter 的方法包括:
StreamWriter sw = new StreamWriter(@"C:"My Documents"ReadMe.txt");
上面的代码使用了 UTF8 编码方法,.NET 把这种编码方法设置为默认的编码方法. 如果要指定其他的编码方法:
- StreamWriter sw = new StreamWriter(@"C:"My Documents"ReadMe.txt", true,
- Encoding.ASCII);
在这个构造函数中, 第二个参数是 Boolean 型, 表示文件是否应以追加方式打开. 构造函数的参数不能仅是一个文件名和一个编码类.
当然, 可以把 StreamWriter 关联到一个文件流上, 以获得打开文件的更多控制选项:
- FileStream fs = new FileStream(@"C:"My Documents"ReadMe.txt",
- FileMode.CreateNew, FileAccess.Write, FileShare.Read);
- StreamWriter sw = new StreamWriter(fs);
FileInfo 不执行返回 StreamWriter 的任何方法.
另外, 如果要创建一个新文件, 并开始给它写入数据, 可以使用下面的代码:
- FileInfo myFile = new FileInfo(@"C:"My Documents"NewFile.txt");
- StreamWriter sw = myFile.CreateText();
与其他流类一样, 在使用完后, 要关闭 StreamWriter:
sw.Close();
写入流可以使用 StreamWriter.Write()的 4 个重载方法来完成. 最简单的方式是写入一个流, 后面加上一个回车换行符:
- string nextLine = "Groovy Line";
- sw.Write(nextLine);
也可以写入一个字符:
- char nextChar = ~a~;
- sw.Write(nextChar);
也可以写入一个字符数组:
- char [] charArray = new char[100];
- // initialize these characters
- sw.Write(charArray);
甚至可以写入字符数组的一部分:
- int nCharsToWrite = 50;
- int startAtLocation = 25;
- char [] charArray = new char[100];
- // initialize these characters
- sw.Write(charArray, startAtLocation, nCharsToWrite);
3.ReadWriteText 示例
ReadWriteText 示例说明了 StreamReader 和 StreamWriter 类的用法. 它非常类似于前面的 ReadBinaryFile 示例, 但假定要读取的文件是一个文本文件, 并显示其内容. 它还可以保存文件(包括在文本框中对文本进行的修改). 它将以 Unicode 格式保存文件.
图 30-9 所示的 ReadWriteText 用于显示前面的 NewFile.aspx 文件. 但这次读取内容会更容易一些.
这里不打算介绍给打开文件对话框添加事件处理程序的详细内容, 因为它们基本上与前面的 BinaryFileReader 示例相同. 与这个示例相同, 打开一个新文件, 将调用 DisplayFile()方法. 其惟一的区别是 DisplayFile 的执行方式, 本例有一个保存文件的选项. 这由另一个菜单项 save 来表示, 这个选项的处理程序调用我们添加到代码中的另一个方法 SaveFile()(注意, 这个新文件总是重写原来的文件 -- 这个示例没有写入另一个文件的选项).
图 30-9
首先看看 SaveFile(), 因为它是最简单的一个函数. 首先利用 StreamReader.WriteLine()方法把文本框中的每行文本依次写入 StreamWriter 流, 并在每行文本的最后加上回车换行符:
- void SaveFile()
- {
- StreamWriter sw = new StreamWriter(chosenFile, false,
- Encoding.Unicode);
- foreach (string line in textBoxContents.Lines)
- sw.WriteLine(line);
- sw.Close();
- }
chosenFile 是主窗体的一个字符串字段, 它包含已经读取的文件的名称(与前面的示例一样). 注意在打开流时指定 Unicode 编码方式. 如果要以其他格式写入文件, 则只需要改变该参数的值. 如果要把文本追加到文件中, 这个构造函数的第二个参数就设置为 true, 但本例不是这样. 在构造时必须为 StreamWriter 设置编码方式, 可以使用只读属性 Encoding.
下面介绍文件的读取方式. 读取过程比较复杂, 因为我们不知道要读取的文件中包含多少行文本 (换言之, 文件中包含多少个(char)13 - (char)10 序列, 因为 char(13) -char(10) 是行末的回车换行符). 解决这个问题的方式是, 先把文件读入一个 StringCollection 类的实例, 该类在 System.Collections.Specialized 命名空间中, 主要用于保存可动态扩展的一组字符串. 它的两个方法是我们感兴趣的: 把字符串添加到集合中的 Add()和把字符串集合复制到一个数组 (一个 System.Array 实例) 中的 CopyTo().StringCollection 对象的每个元素包含文件中的一行文本.
DisplayFile()方法调用另一个方法 ReadFileIntoStringCollection(), 来读取文件. 之后, 就知道文件中有多少行文本了. 把 StringCollection 复制到大小固定的数组中, 并把数组中的内容填充到文本框中. 在进行复制时, 只复制了字符串的引用, 没有复制字符串本身, 所以该过程的执行效率很高:
- void DisplayFile()
- {
- StringCollection linesCollection = ReadFileIntoStringCollection();
- string [] linesArray = new string[linesCollection.Count];
- linesCollection.CopyTo(linesArray, 0);
- this.textBoxContents.Lines = linesArray;
- }
StringCollection.CopyTo()的第二个参数表示目标数组中的下标, 我们从该下标指定的位置开始复制集合.
下面看看 ReadFileIntoStringCollection()方法. 使用 StreamReader 读取每一行文本. 编译时需要计算读取的字符数, 以确保不超出文本框的范围:
- StringCollection ReadFileIntoStringCollection()
- {
- const int MaxBytes = 65536;
- StreamReader sr = new StreamReader(chosenFile);
- StringCollection result = new StringCollection();
- int nBytesRead = 0;
- string nextLine;
- while ( (nextLine = sr.ReadLine()) != null)
- {
- nBytesRead += nextLine.Length;
- if (nBytesRead> MaxBytes)
- break;
- result.Add(nextLine);
- }
- sr.Close();
- return result;
- }
这就是该示例的完整代码.
如果运行 ReadWriteText, 读取 NewFile.aspx 文件, 然后保存它, 该文件的格式就是 Unicode. 任何常用的 Windows 应用程序 (Notepand,Wordpad) 都没有提供这种格式, 甚至 ReadWriteText 示例也只能在 Windows NT/2000/XP/2003 下正确读取和显示文件. 因为 Windows 9x 不支持 Unicode, 像 Notepad 这样的应用程序不能识别其他平台上的 Unicode 文件(如果从 Wrox Press 网站上下载了这个示例, 就可以试试). 但是, 如果使用前面的 ReadBinaryFile 示例显示文件, 就会立即看出它们的区别, 如图 30-10 所示. 最前面的两个字节表示文件的格式是 Unicode, 之后, 每个字符都用两个字节来表示. 这是非常明显的, 因为在这个文件中, 每个字符的高位字节都是 0, 所以每隔一个字节就显示 x00.
GPS 平台, 网站建设, 软件开发, 系统运维, 找森大网络科技!
http://cnsendnet.taobao.com/
来自森大科技官方博客
- http://www.cnsendblog.com/index.php/?p=459
来源: http://www.bubuko.com/infodetail-3446364.html