16.9 使用StreamWriter和StreamReader类型
当需要读写基于字符的数据(比如字符串)的时候,StreamReader和StreamWriter就非常有用了。它们都默认使用Unicode字符,当然我们也可以提供一个正确配置的System.Text.Encoding对象的实例来改变默认配置。为了使例子更简单,假设默认的Unicode编码能满足我们的需求。
StreamReader和相关的StringReader(本章后面会讨论)一样,它们都从TextReader抽象类型派生。TextReader基类为这些派生类型提供了一套非常有限的功能,特别是读取字符流。
StreamWriter类型(和后面会讨论的StringWriter一样)从TextWriter抽象基类派生。这个类定义了一些成员,使得派生的类型能向某个字符流写入文本数据。图16-7显示了这些新的I/O对象之间的关系。
为了帮助读者理解StreamWriter和StringWriter类主要的功能,表16-7列举了一些TextWriter抽象基类的核心成员。
表16-7 TextWriter核心成员
|
成 员 |
作 用 |
|
Close() |
关闭当前编写器并释放任何与该编写器关联的系统资源,在这个过程中缓冲区将被自动清理 |
|
Flush() |
清理当前编写器的所有缓冲区,使所有缓冲数据写入基础设备,但是不关闭编写器 |
|
NewLine |
代表派生的编写器类的行结束符字符串。默认行结束符字符串是回车符后接一个换行符(\r\n) |
|
Write() |
将一行写入文本流,不跟行结束符 |
|
WriteLine() |
将一行写入文本流,后跟行结束符 |
注解 TextWriter最后两个成员可能对读者来说很熟悉。前面说过,System.Console类型就有Write()和WriteLine()成员来向标准输出设备写入文本数据。其实,Console.In属性包装了一个TextWrite,Console.Out属性包装了一个TextReader。
派生的StreamWriter类提供了对Write()、Close()和Flush()方法的有效实现,而且还定义了AutoFlush属性。如果把这个属性设置为true的话,StreamWriter会在每次执行一个写操作后,立即写入数据并清理缓冲区。设置AutoFlush为false能获得更好的性能,这样的话,使用StreamWriter完成了写操作后需要调用Close()。
16.9.1 写文本文件
现在举一个使用StreamWriter类型的例子。下面的类使用File.CreateText()方法新建一个reminders.txt文件。使用返回的StreamWriter对象向新建的文件增加一些文本数据,代码如下:
static void Main(string[] args)
{
Console.WriteLine("***** Fun with StreamWriter / StreamReader *****\n");
// 得到一个StreamWriter对象并写入字符串数据。
StreamWriter writer = File.CreateText("reminders.txt");
writer.WriteLine("Don't forget Mother's Day this year...");
writer.WriteLine("Don't forget Father's Day this year...");
writer.WriteLine("Don't forget these numbers:");
for(int i = 0; i < 10; i++)
writer.Write(i + " ");
// 插入一个新行。
writer.Write(writer.NewLine);
// Close()自动实现Flush操作!
writer.Close();
Console.WriteLine("Created file and wrote some thoughts...");
}
运行程序来检查新建文件的内容(如图16-8所示)。

图16-8 *.txt文件的内容
16.9.2 从文本文件读
现在需要理解怎样使用相应的StreamReader类型通过编程从文件读取数据。前面说过,这个类从TextReader派生,表16-8列举了一些它的功能。
表16-8 TextReader主要成员
|
成 员 |
作 用 |
|
Peek() |
返回下一个可用字符,而不更改读取器位置,返回-1表示已经到了流的尾部 |
|
Read() |
从输入流中读取数据 |
|
ReadBlock() |
从当前流中读取最大计数字符,并从索引开始将该数据写入缓冲区 |
|
ReadLine() |
从当前流中读取一行字符,并将数据作为字符串返回(返回null代表EOF) |
|
ReadToEnd() |
读取从当前位置到流结尾的所有字符,并将它们作为一个字符串返回 |
如果扩展当前的MyStreamWriterReader类来使用StreamReader,可以从reminders.txt读取文本数据,代码如下:
static void Main(string[] args)
{
Console.WriteLine("***** Fun with StreamWriter / StreamReader *****\n");
...
// 现在开始从文件读数据。
Console.WriteLine("Here are your thoughts:\n");
StreamReader sr = File.OpenText("reminders.txt");
string input = null;
while ((input = sr.ReadLine()) != null)
{
Console.WriteLine (input);
}
}
运行程序后会发现Thoughts.txt里的字符数据显示到了控制台。
16.9.3 直接创建StreamWriter/StreamReader类型
可能读者还有一点困惑,那就是使用System.IO的这些类型可以有很多种方法实现相同的结果。比如,我们可以使用File或者FileInfo的CreateText()方法来获取StreamWriter。其实,还有一个方法来使用StreamWriter和StreamReader:直接创建它们。例如,现在的应用程序可以如下修改:
static void Main(string[] args)
{
Console.WriteLine("***** Fun with StreamWriter / StreamReader *****\n");
// 得到一个StreamWriter然后写字符串数据。
StreamWriter writer = new StreamWriter("reminders.txt");
...
// 从文件读取数据。
StreamReader sr = new StreamReader("reminders.txt");
...
}
使用这么多看上去差不多的方法实现文件I/O操作虽说让我们有点困惑,但是这样的确增加了很多灵活性。无论如何,已经看到了怎样使用StreamWriter和StreamReader类型从指定文件写入、读取信息,下面再来研究StringWriter和StringReader类的作用。
源代码 StreamWriterReaderApp项目的源代码位于Chapter 16子目录下。






