7 流文件及基于文本的应用谢新冲.docx
- 文档编号:28406601
- 上传时间:2023-07-13
- 格式:DOCX
- 页数:62
- 大小:238.31KB
7 流文件及基于文本的应用谢新冲.docx
《7 流文件及基于文本的应用谢新冲.docx》由会员分享,可在线阅读,更多相关《7 流文件及基于文本的应用谢新冲.docx(62页珍藏版)》请在冰豆网上搜索。
7流文件及基于文本的应用谢新冲
第7章流、文件及基于文本的应用
与外部设备和其他计算机进行交流的输入输出操作,尤其是对磁盘的文件操作,是计算机程序重要而必备的功能,本章中介绍流式输入输出、文件及目录管理,并介绍基于文本的应用的一些问题。
7.1流及二进制输入输出
7.1.1流
为进行数据的输入/输出操作,C#中把不同的输入/输出源(键盘、文件、网络连接、内存等)抽象表述为“流”(stream)。
Stream类是抽象类,它有三个重要的子类,分别针对的是不同的存取对象:
FileStream类表示文件操作,MemoryStream表示内存操作,BufferedStream表示缓冲处理。
需要说明的是,尽管System.Net.Sockets.NetworkStream类并不属于System.IO名字空间,但该类也可以通过使用网络sockets执行基于流的I/O。
1.Stream类
抽象的Stream类包含了流中所需要的许多属性和操作,如表71和表72所示。
表71Stream类的属性
属性
描述
CanRead
如果当前流支持读操作,该属性为true
CanSeek
如果当前流支持搜索操作,该属性为true
CanWrite
如果当前流支持写操作,该属性为true
Length
返回以字节数表示的流长度
Position
返回支持搜索操作的流的当前位置
表72Stream类中的一些重要方法
方法
描述
BeginRead,EndRead
异步读操作的开始和结束
BeginWrite,EndWrite
异步写操作的开始和结束
Close
流的关闭
Flush
流的刷新
Read
从流中读出一个字节序列
ReadByte
从流中读出一个字节
Seek
设定流内部的位置
SetLength
设定流的长度
Write
向流中写入一个字节序列
WriteByte
向流中写入一个字节
这些属性和方法中涉及了流的读写的各个方面。
读写操作的4个方法如下:
intReadByte();
intRead(byte[]array,intoffset,intcount);
voidWriteByte(bytevalue);
voidWrite(byte[]array,intoffset,intcount);
其中ReadByte()将读入的字节转成整数并返回,如果没有读到字节,则返回-1。
Read()方法返回的所读字节的数目。
通过BeginRead()、EndRead()、BeginWrite()和EndWrite()等方法,Stream类可以支持异步I/O操作。
需要解释的是Seek()方法,它表示在流中对搜索指针进行定位,用来决定下一步的读或写操作的位置。
在这样的流中,其CanSeek属性值为true,并且可以使用其Seek()方法来设定指针的位置。
Seek()方法需要两个参数:
用来表示搜索指针移动距离的数值以及用来确定指针移动的参照位置。
参照位置是SeekOrigin的枚举成员,可以是下面3种情况之一:
1)SeekOrigin.Begin(文件的开头)
2)SeekOrigin.Current(文件中指针的当前位置)
3)SeekOrigin.End(文件的结尾)
下面的代码展示了如何在文件中进行搜索处理:
aStream.Seek(200,SeekOrigin.Begin);//从开头移到200位置
aStream.Seek(0,SeekOrigin.End);//移到文件尾
aStream.Seek(-20,SeekOrigin.Current);//从当前位置反向移动20
2.FileStream类
FileStream是从Stream中直接派生而来的。
FileStream对象既可以从文件中读出内容,也可以向文件中写入内容,并且可以处理字节、字符、字符串以及其他一些数据类型。
该对象也可以被用来执行标准的输入输出及标准错误的输出。
应该注意FileStream对象通常不单独使用,因为其应用比较接近于底层。
该对象只能对字节进行读写操作,因此在使用时必须把字符串、数字以及对象都转换成字节才能将其传递到FileStream中。
鉴于此,FileStream通常被包装到其他一些类中加以使用,如BinaryWriter或者TextReader,这些类可以处理高层的数据结构。
FileStream类具有很多形式的构造方法,因而可以根据以下这些参数的不同组合而采用不同的FileStreams构造方法:
1)文件名
2)文件句柄——用来表示文件句柄的一个整数
3)访问模式——FileMode枚举值之一
4)读/写权限——FileAccess枚举值之一
5)共享模式——FileShare枚举值之一
6)缓冲器大小
表73、表74和表75分别说明了文件的访问模式、访问权限以及共享模式。
表73FileMode枚举的文件访问模式
访问模式
说明
Append
如果文件存在,则打开该文件并将数据添加到文件尾;如果文件不存在,则创建一个新文件
Create
指定创建一个新文件;如果已经存在一个同名文件,则旧文件被覆盖
CreateNew
指定创建一个新文件;如果已经存在同名文件,则产生IOException异常
Open
打开一个已经存在的文件;如果该文件不存在则产生异常
OpenOrCreate
打开一个文件;如果所打开的文件不存在,则创建一个新文件
Truncate
打开一个已经存在的文件,并且从头开始覆盖其数据
表74FileAccess枚举的文件访问权限
访问权限
说明
Read
可以从文件中读出数据
Write
可以向文件中写入数据
ReadWrite
既可以读出数据,也可以写入数据
表75FileShare枚举的共享标记
共享标记
说明
None
在文件被关闭之前,不能被任何其他进程(包括当前使用进程)再次打开
Read
文件支持共享的读操作访问
Write
文件支持共享的写操作访问
ReadWrite
文件支持共享的读写操作访问
例如,要创建一个文件,并使该文件支持共享的读操作:
FileStreamfs=newFileStream(
@"c:
\temp\foo.txt",FileMode.Create,FileAccess.Read);
FileStream可以通过同步或者异步方式创建,同时,除了从Stream中继承的属性之外,还增加IsAsync属性。
并且,该类中还增加表76中所列出的方法:
表76从Stream类中继承而来的FileStream所添加的新方法
方法
说明
GetHandle
为基础文件返回操作系统文件句柄
Lock
防止其他进程访问整个文件或者某一部分文件
Unlock
解除以前的锁定
GetHandle()方法能够返回一个可以用于本地操作系统函数(如Win32中的ReadFile())的标识符,但该方法一定要慎用。
如果使用文件句柄对基础文件作了某些改动,然后又试图在该文件上使用FileStream,则有可能会破坏文件中的数据。
FileStream类在操作时,可能会产生异常,下面是几种不同的异常:
1)ArgumentException——路径为空字符
2)ArgumentNullException——路径是一个null引用
3)SecurityException——对文件没有操作权限
4)FileNotFoundException——找不到文件
5)IOException——发生了一些其他的I/O错误,例如指定了一个错误的驱动器符
6)DirectoryNotFoundException——目录不存在
例71FileStream.cs通过FileStream来读写文件的内容。
1usingSystem;
2usingSystem.IO;
3classTest
4{
5staticvoidMain()
6{
7try
8{
9FileStreamfsw=newFileStream("test.dat",
10FileMode.Create,FileAccess.Write);
11
12//Writesomedatatothestream;
13fsw.WriteByte(33);
14fsw.Write(newbyte[]{34,35,36},0,3);
15fsw.Close();
16
17FileStreamfsr=newFileStream("test.dat",
18FileMode.Open,FileAccess.Read);
19Console.WriteLine(fsr.ReadByte());
20Console.WriteLine(fsr.ReadByte());
21Console.WriteLine(fsr.ReadByte());
22Console.WriteLine(fsr.ReadByte());
23}
24catch(Exceptione)
25{
26Console.WriteLine("Exception:
"+e.ToString());
27}
28}
29}
3.MemoryStream
MemoryStream也是从Stream中直接继承而来的,它使用内存代替文件来存储流,但其处理与FileStream非常类似。
MemoryStream把数据以字节数组的形式存储在内存中,并且可以用来代替应用程序中临时文件的作用。
如同FileStream一样,MemoryStream也有很多构造方法。
其中两种比较常用:
MemoryStream();
MemoryStream(byte[]);
用这里的第一个构造方法建立MemoryStream,当向流的末尾写入数据时,MemoryStream可以随之扩张。
用第二个构造函方法所建立的是基于指定的字节数组的MemoryStream类的新实例,这样建立的流无法调整大小。
除了从Stream继承的属性之外,MemoryStream还增加了一个Capacity属性。
Capacity属性可以用来指出当前分配到流上的字节数。
当使用基于字节数组的流时,这一属性是非常有用的,因为该属性可以告知数组的大小,而Length属性则可以指出当前正被使用的字节数。
MemoryStream不能够执行异步的读/写方法,因为对内存的I/O不需要这种特性。
但该对象可以执行下面这3种附加方法:
1)GetBuffer()——返回对流中的字节数组的一个引用
2)ToArray()——将所有内容写入到字节数组中
3)WriteTo()——将流中的内容写入到另一个Stream中
例72MemoryStreamTest.cs使用MemoryStreamTest.cs对内存进行操作。
1usingSystem;
2usingSystem.IO;
3classTest
4{
5staticvoidMain()
6{
7try
8{
9byte[]ary={33,34,35,36,37};
10intb;
11
12MemoryStreammsr=newMemoryStream(ary);
13MemoryStreammsw=newMemoryStream();
14
15while((b=msr.ReadByte())!
=-1)
16{
17msw.WriteByte((byte)(b+3));
18}
19byte[]result=msw.ToArray();
20
21foreach(bytebtinresult)
22Console.WriteLine(bt);
23}
24catch(IOExceptione)
25{
26Console.WriteLine("Exception:
"+e.ToString());
27}
28}
29}
4.BufferedStream类
BufferedStream可以提高读写操作的执行效率,因为该类可以把数据缓存到内存中,从而减少了对操作系统的调用次数。
BufferedStream不能够单独使用,而应该将其包装到流的其他一些类型中,特别是下面所描述的BinaryWriter和BinaryReader类型的流中。
7.1.2使用流进行二进制输入输出
1.BinaryReader和BinaryWriter
BinaryReader和BinaryWriter可以用来进行二进制I/O,也就是用来读写基本的数据类型(如int,double等),而不是原始的字节类型。
BinaryReader和BinaryWriter类不是Stream类的子类,但它是对Stream流进行的包装,在构造BinaryReader和BinaryWriter对象时,需要一个Stream对象作为其参数。
如:
newBinaryReader(myStream);
实际上,这两种类主要是在基本类型和原始字节之间进行转换,因此它们需要处理能够对字节进行I/O的一些基本的Stream对象,如FileStream或者MemoryStream。
这两种类都有一个BaseStream属性,通过该属性可以得到对基本的Stream对象的引用。
下面的表77列出了BinaryWriter类的一些方法。
表77BinaryWriter类的方法列表
方法
说明
Close
关闭BinaryWriter并释放所有与之相关的资源
Flush
对BinaryWriter缓冲区中未写入的数据执行写入操作
Seek
移动搜索指针
Write
向流中写入一个值
Write7BitEncodedInt
以压缩格式写入一个32位整数
Write()方法至少提供了18种重载形式,它们能对对.NET中的基本类型执行写操作。
这些类型包括:
1)整数类型(sbyte,short,int,long,byte,ushort,uint,ulong)
2)实数类型(float,double,decimal)
3)byte及byte数组
4)char以及char数组
5)字符串(string)
BinaryReader与BinaryWriter有很相似的功能,有多个不同名字的ReadXXX()方法。
例如,在BinaryWriter中,可以有Write(Int16)方法和Write(Char)方法,而在BinaryReader中则只能有ReadInt16()方法和ReadChar()方法。
其原因是显而易见的:
当执行写操作时,writer对象能够根据Write()的参数推断出写入的内容;而当执行读操作时,面对一个字节流,reader对象并不知道应该如何把这些字节组织到一起。
必须通过调用某个特定的函数,才能够告诉reader对象如何把字节流组织到一起。
2.用Stream流进行二进制输入输出
BinaryReader及BinaryWriter可以对Stream进行包装,从而进行二进制的原始数据的输入输出。
例73BinaryFileStream.cs以二进制格式向文件中写入数据,然后再从该文件中读出数据。
1usingSystem;
2usingSystem.IO;
3classTest
4{
5staticvoidMain()
6{
7try
8{
9FileStreamds=newFileStream("test.dat",
10FileMode.Create,FileAccess.ReadWrite);
11
12BinaryWriterbw=newBinaryWriter(ds);
13
14//Writesomedatatothestream;
15bw.Write("Astring");
16bw.Write(142);
17bw.Write(97.4);
18bw.Write(true);
19
20//Openitforreading;
21BinaryReaderbr=newBinaryReader(ds);
22//Movebacktothestart;
23br.BaseStream.Seek(0,SeekOrigin.Begin);
24//Readthedata;
25Console.WriteLine(br.ReadString());
26Console.WriteLine(br.ReadInt32());
27Console.WriteLine(br.ReadDouble());
28Console.WriteLine(br.ReadBoolean());
29}
30catch(Exceptione)
31{
32Console.WriteLine("Exception:
"+e.ToString());
33}
34}
35}
例中创建了一个FileStream对象,用来对文件进行操作。
创建对象时的第二个参数决定文件以什么样的方式打开,在本例中,该参数被设置为FileMode.Create,表示要创建一个新文件,或者覆盖已经存在的同名文件。
第三个参数决定文件的访问权限,本例中由于要对文件进行读写操作,因而使用FileAccess.ReadWrite参数。
将FileStream的创建放在一个try{}catch{}中,是一个比较好的做法,因为在打开和写入文件时往往会出现很多错误。
FileStream可以对字节进行读写,操作起来通常很不方便,因此FileStream经常被包装到其他能够对字节进行转换的类中使用。
在上面所举的例子中,使用了一个BinaryWriter类,该类能够接收.NET中的原始类型,并将其转换为字节。
然后再把字节传送到FileStream类中。
BinaryWriter类有许多重载的Write()方法,每种方法针对一种特定的原始类型。
在本例中,共使用了4种这样的方法,分别用来写入字符串、整数、浮点数值和bool值。
程序中然后创建一个BinaryReader对象用来从FileStream中读取数据。
在使用BinaryReader之前,必须首先退回到文件的开头,即调用Seek()方法对FileStream重新定位。
然后就很容易地从文件中读取数据,将读得的数据显示出来,如图71所示。
图71创建了一个FileStream对象
7.2文本输入输出
到目前为止,已经讨论了将数据表示为一系列字节的二进制I/O,下面将介绍可以用于字符I/O的一些类。
7.2.1使用Reader和Writer的文本I/O
TextWriter类和TextReader类是基于文本的抽象类,它们的重要子类包括:
StreamWriter、StreamReader,处理流的操作;StringWriter、StringReader处理字符串的操作。
注意:
对于C程序员来说,StreamWriter类似于printf()或者fprintf(),而StringWriter类似于sprintf()。
1.TextWriter类
TextWriter是一个抽象基类,它包含下面一些子类:
1)用来为浏览器客户端编写HTML的HtmlTextWriter。
2)用来向ASP.NET网页中的HTTP响应对象写入文本的HttpWriter。
3)使用缩进控制写入文本的IndentedTextWriter。
4)向流中写入字符的StreamWriter。
5)向字符串中写入字符的StringWriter。
TextWriter有3个属性:
Encoding,用来返回产生输出的字符编码;FormatProvider,用来引用对文本进行格式化的对象;NewLine,用来返回当前使用平台上所用的行结束符。
行结束符默认为“\r\n”(即回车符后紧跟一个换行符),但也可以改为“\r”或者“\n"。
TextWriter类中的方法如表78所示。
表78TextWriter类的方法
方法
说明
Close
关闭TextWriter并释放所有与之相关的资源
Dispose
释放与TextWriter相关的资源
Flush
将保留在TextWriter缓冲区中的未录入数据写入
Synchronized
创建TextWriter对象的一个线程安全包
Write
向流中写入数据,详见下面的描述
WriteLine
向流中写入数据并换行
TextWriter的Write()方法是将数据以字符串的方式写出。
要注意与其他类相比:
Stream的Write()方法写的是字节,BinaryWriter的Write()方法是将基本数据类型以原始的方式写出。
Write()方法有多种重载形式,分别执行将各种类型(Char、Boolean、Int32等)写入到流中。
WriteLine()方法也有同样的一套重载形式,区别只是多了一个换行符,如表79所示。
表79WriteLine()类的重载形式
重载形式
说明
WriteLineO
写入新的一行
WriteLine(char)
写入某一个字符
WriteLine(char[])
写入一个字符数组
WriteLine(char[],int,int)
写入字符数组的一部分
WriteLine(string)
写入一个字符串
WriteLine(bool)
写入一个Boolean值,即“true”或者“false”
WriteLine(decimal)
写入一个十进制数值
WriteLine(int)
写入一个整数
WriteLine(long)
写入一个长整型的数值
WriteLine(object)
对对象调用ToString()
WriteLine(float)
写入单精度浮点数值
WriteLine(string,object)
写入包含一个对象的格式化字符串
WriteLine(string,object,object)
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 流文件及基于文本的应用谢新冲 文件 基于 文本 应用 谢新冲