理论上可以使用FileStream类读取和显示文本文件前面已经介绍了这个类上面显示NewFiletxt文件的格式不太容易理解但这并不是FileStream类的问题——而在于我们在文本框中显示结果所使用的方式
如果知道某个文件包含文本通常就可以使用StreamReader 和 StreamWriter类更方便地读写它们这是因为这些类工作的级别比较高特别适合于读写文本它们执行的方法可以根据流的内容自动检测出停止读取文本较方便的位置特别是
●这些类执行的方法可以一次读写一行文本(StreamReaderReadLine() 和 StreamWriterWriteLine())在读取文件时流会自动确定下一个回车符的位置并在该处停止读取在写入文件时流会自动把回车符和换行符添加到文本的末尾
●使用StreamReader 和 StreamWriter类就不需要担心文件中使用的编码方式(文本格式)了可能的编码方式是ASCII(一个字节表示一个字符)或者基于Unicode的格式UNICODEUTF和 UTFWindows x系统上的文本文件总是ASCII格式因为Windows x系统不支持Unicode但Windows NTXP和都支持Unicode所以文本文件除了包含ASCII数据之外理论上可以包含UnicodeUTF或 UTF数据其约定是如果文件是ASCII格式就只包含文本如果是Unicode格式就用文件的前两个或三个字节来表示这几个字节可以设置为表示文件中格式的值的特定组合
这些字节称为字节码标记在使用标准Windows应用程序打开一个文件时例如Notepad 或 WordPad不需要考虑这个问题因为这些应用程序都支持不同的编码方法会自动正确地读取文件StreamReader类也是这样它可以正确读取任何格式的文件而StreamWriter类可以使用任何一种编码技术格式化它要写入的文本另一方面如果要使用FileStream类读取和显示文本文件就不必自己处理这个过程了
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 DocumentsReadMetxt);
另外如果指定UTF编码方法
StreamReader sr = new StreamReader(@C:My DocumentsReadMetxt
EncodingUTF);
使用类SystemTextEncoding上的几个属性之一就可以指定编码方法
这个类是一个抽象基类可以根据这个类定义许多类其方法可执行实际的文本编码每个属性都返回相应类的一个实例可以使用的属性包括
●ASCII
●Unicode
●UTF
●UTF
●BigEndianUnicode
下面的示例解释了如何把StreamReader关联到FileStream上其优点是可以显式指定是否创建文件和共享许可如果直接把StreamReader关联到文件上就不能这么做
FileStream fs = new FileStream(@C:My DocumentsReadMetxt
FileModeOpen FileAccessRead FileShareNone);
StreamReader sr = new StreamReader(fs);
对于本例指定StreamReader查找字节码标记以确定使用了什么编码方法以后的示例也是这样从一个FileInfo实例中获得StreamReader
FileInfo myFile = new FileInfo(@C:My DocumentsReadMetxt);
StreamReader sr = myFileOpenText();
与FileStream一样应在使用后关闭StreamReader如果没有这样做就会致使文件一直锁定因此不能执行其他过程(除非使用FileStream构造StreamReader和特定的FileShare ShareReadWrite)
srClose();
介绍完实例化StreamReader后就可以用该实例作一些工作了与FileStream一样我们仅指出可以用于读取数据的许多方式您应在SDK文档说明书中查阅其他不太常用的StreamReader方法
所使用的最简单的方式是ReadLine()该方法一次读取一行但返回的字符串中不包括标记该行结束的回车换行符
string nextLine = srReadLine();
另外还可以在一个字符串中提取文件的所有剩余内容(严格地说是流的全部剩余内容)
string restOfStream = srReadToEnd();
可以只读取一个字符
int nextChar = srRead();
Read()的重载方法可以把返回的字符转换为一个整数如果到达流的尾端就返回
最后可以用一个偏移值把给定个数的字符读到数组中
// to read characters in
int nChars = ;
char [] charArray = new char[nChars];
int nCharsRead = srRead(charArray nChars);
如果要求读取的字符数多于文件中剩余的字符数nCharsRead应小于nChars
StreamWriter类
StreamWriter类的工作方式与StreamReader的类似但StreamWriter只能用于写入文件(或另一个流)构造StreamWriter的方法包括
StreamWriter sw = new StreamWriter(@C:My DocumentsReadMetxt);
上面的代码使用了UTF编码方法NET把这种编码方法设置为默认的编码方法如果要指定其他的编码方法
StreamWriter sw = new StreamWriter(@C:My DocumentsReadMetxt true
EncodingASCII);
在这个构造函数中第二个参数是Boolean型表示文件是否应以追加方式打开构造函数的参数不能仅是一个文件名和一个编码类
当然可以把StreamWriter关联到一个文件流上以获得打开文件的更多控制选项
FileStream fs = new FileStream(@C:My DocumentsReadMetxt
FileModeCreateNew FileAccessWrite FileShareRead);
StreamWriter sw = new StreamWriter(fs);
FileInfo不执行返回StreamWriter的任何方法
另外如果要创建一个新文件并开始给它写入数据可以使用下面的代码
FileInfo myFile = new FileInfo(@C:My DocumentsNewFiletxt);
StreamWriter sw = myFileCreateText();
与其他流类一样在使用完后要关闭StreamWriter
swClose();
写入流可以使用StreamWriterWrite()的个重载方法来完成最简单的方式是写入一个流后面加上一个回车换行符
string nextLine = Groovy Line;
swWrite(nextLine);
也可以写入一个字符
char nextChar = ~a~;
swWrite(nextChar);
也可以写入一个字符数组
char [] charArray = new char[];
// initialize these characters
swWrite(charArray);
甚至可以写入字符数组的一部分
int nCharsToWrite = ;
int startAtLocation = ;
char [] charArray = new char[];
// initialize these characters
swWrite(charArray startAtLocation nCharsToWrite);
ReadWriteText示例
ReadWriteText示例说明了StreamReader和StreamWriter类的用法它非常类似于前面的ReadBinaryFile示例但假定要读取的文件是一个文本文件并显示其内容它还可以保存文件(包括在文本框中对文本进行的修改)它将以Unicode格式保存文件
图所示的ReadWriteText用于显示前面的NewFileaspx文件但这次读取内容会更容易一些
这里不打算介绍给打开文件对话框添加事件处理程序的详细内容因为它们基本上与前面的BinaryFileReader示例相同与这个示例相同打开一个新文件将调用DisplayFile()方法其惟一的区别是DisplayFile的执行方式本例有一个保存文件的选项这由另一个菜单项save来表示这个选项的处理程序调用我们添加到代码中的另一个方法SaveFile()(注意这个新文件总是重写原来的文件——这个示例没有写入另一个文件的选项)
=) windowopen(_//jpg); src=_//jpg onload=javascript:if(thiswidth>)thiswidth=;setTimeout(if(documentgetElementById(\_//jpg\)height>\\)documentgetElementById(\_//jpg\)height=\\;); border= twffan=done>
图
首先看看SaveFile()因为它是最简单的一个函数首先利用StreamReader
WriteLine()方法把文本框中的每行文本依次写入StreamWriter流并在每行文本的最后加上回车换行符
void SaveFile()
{
StreamWriter sw = new StreamWriter(chosenFile false
EncodingUnicode);
foreach (string line in textBoxContentsLines)
swWriteLine(line);
swClose();
}
chosenFile是主窗体的一个字符串字段它包含已经读取的文件的名称(与前面的示例一样)注意在打开流时指定Unicode编码方式如果要以其他格式写入文件则只需要改变该参数的值如果要把文本追加到文件中这个构造函数的第二个参数就设置为true但本例不是这样在构造时必须为StreamWriter设置编码方式可以使用只读属性Encoding
下面介绍文件的读取方式读取过程比较复杂因为我们不知道要读取的文件中包含多少行文本(换言之文件中包含多少个(char) – (char)序列因为char() –char()是行末的回车换行符)解决这个问题的方式是先把文件读入一个StringCollection类的实例该类在SystemCollectionsSpecialized命名空间中主要用于保存可动态扩展的一组字符串它的两个方法是我们感兴趣的把字符串添加到集合中的Add()和把字符串集合复制到一个数组(一个SystemArray实例)中的CopyTo()StringCollection对象的每个元素包含文件中的一行文本
DisplayFile()方法调用另一个方法ReadFileIntoStringCollection()来读取文件之后就知道文件中有多少行文本了把StringCollection复制到大小固定的数组中并把数组中的内容填充到文本框中在进行复制时只复制了字符串的引用没有复制字符串本身所以该过程的执行效率很高
void DisplayFile()
{
StringCollection linesCollection = ReadFileIntoStringCollection();
string [] linesArray = new string[linesCollectionCount];
linesCollectionCopyTo(linesArray );
thistextBoxContentsLines = linesArray;
}
StringCollectionCopyTo()的第二个参数表示目标数组中的下标我们从该下标指定的位置开始复制集合
下面看看ReadFileIntoStringCollection()方法使用StreamReader读取每一行文本编译时需要计算读取的字符数以确保不超出文本框的范围
StringCollection ReadFileIntoStringCollection()
{
const int MaxBytes = ;
StreamReader sr = new StreamReader(chosenFile);
StringCollection result = new StringCollection();
int nBytesRead = ;
string nextLine;
while ( (nextLine = srReadLine()) != null)
{
nBytesRead += nextLineLength;
if (nBytesRead > MaxBytes)
break;
resultAdd(nextLine);
}
srClose();
return result;
}
这就是该示例的完整代码
如果运行ReadWriteText读取NewFileaspx文件然后保存它该文件的格式就是Unicode任何常用的Windows应用程序(NotepandWordpad)都没有提供这种格式甚至ReadWriteText示例也只能在Windows NT//XP/下正确读取和显示文件因为Windows x不支持Unicode像Notepad这样的应用程序不能识别其他平台上的Unicode文件(如果从Wrox Press网站上下载了这个示例就可以试试)但是如果使用前面的ReadBinaryFile示例显示文件就会立即看出它们的区别如图所示最前面的两个字节表示文件的格式是Unicode之后每个字符都用两个字节来表示这是非常明显的因为在这个文件中每个字符的高位字节都是所以每隔一个字节就显示x
//jpg onclick=if(thiswidth>=) windowopen(_//jpg); src=_//jpg onload=javascript:if(thiswidth>)thiswidth=;setTimeout(if(documentgetElementById(\_//jpg\)height>\\)documentgetElementById(\_//jpg\)height=\\;); border= twffan=done>
图