在上面的内容中,我们讲述了如何去打开一个文件,接下来我们来看看如何去对一个打开的文件进行读写操作。
首先是读操作,FileStream类定义了两个从文件中读取字节的方法,分别是Read()和ReadByte(),其中ReadByte()是读取一个字节,而Read()是读取一个字节块。
当我们定义一个FileStream引用对象时,如果它不指向任何对象,这时我们可以将其初始化为null,这样做的好处在于如果最后我们需要关闭某个数据流对象,那么如果这个数据流对象为空,那么关闭它就是出现异常,通过初始化为null,我们可以在最后通过if语句来判断这个数据流是否存在,如果存在,我么才用Close()方法进行关闭。
下面简单讲述一个两个读取字节的函数。
ReadByte的通用形式为:
int ReadByte()
调用时会从文件中读取一个字节并返回一个整数值,如果到达文件末尾,该方法返回-1。
Read()的通用形式为:
int Read(byte[] array,int offset,int count)
该方法从数据流中顺序读取count个字节,从array[offset]开始将这些字节依次写入array数组,方法返回成功读取的字节总数。
与读取字节相对的是向文件中写入字节,与上面读取函数相对应的同样存在两个写入文件的函数,它们分别为Write()和WriteByte()方法。这两个函数的介绍如下所示:
void WriteByte(byte value)
该方法将value指定的字节写入到文件中,下面的方法是将一个字节数组写入到文件中,方法原型如下:
void Write(byte[] array,int offset,int count);
该方法将array数组中从下标offset的位置开始写入count个字节到文件中。
如果底层数据流未打开以进行输出,则会抛出NotSupportedException异常,如果数据流已经关闭则抛出ObjectDisposedException异常。
需要注意的是,在执行文件输出时,输出的内容并不是直接写入到真正的物理设备中,操作系统会把这些输出的内容先保存到缓冲区中,当缓冲区满时再一次性的写入大量的数据。当然如果我们希望在缓冲区满前就将数据写入到物理设备中也是可以的,这时我们需要使用Flush()函数。
在处理完输出文件时,必须使用Close()方法将文件关闭。
在上面,我们讲述了如何以字节的方式读写文件,然而我们更习惯与基于字符的文件操作,这时我们就需要将字节数据流转换为字符数据流。下面我们讲述两个用于文件操作的字符数据流类型。
StreamReader类派生于TextReader类,是基于字符的数据流类型,当我们需要创建基于字符的数据流对象时我们需要把数据流包装成StreamReader对象。此时我们需要用到一种常用的构造函数,如下所示:
StreamReader(Stream stream);
该构造函数以一个数据流对象作为参数,如果参数为空,则会抛出ArgumentNullException异常,如果stream指定的数据流未打开进行读取,则会抛出ArgumentException异常。
我们还有一种比较简洁的方式来打开文件,这时我们需要借助于另一种常用的构造函数:
StreamReader(String path);
参数path中指定了要打开的文件的名称(包含文件名和完整的文件路径信息)。
这里补充一点,那就是StreamReader类提供了检测是否到达数据流末端的EndOfStream属性,当到达末端时,该属性为true。
与读操作相对应,存在StreamWriter类实现基于字符的写操作,该类派生于TextWriter类。
StreamWriter类同样也存在两个常用的构造函数,如下所示:
StreamWriter(Stream stream);
StreamWriter(string path);
StreamWriter(string path,bool append);
第一种是将一个Stream对象包装在StreamWriter类中;第二种是打开path参数指定的文件进行写操作;第三种和第二种相似,其中append参数指定是否将写入的内容追加到文件的末尾,如果append为true,则将输入的内容追加到文件的末尾。