【Stream—2】关于StreamReader的知识分享
今天我们来简单的介绍一下StreamReader,在将StreamReader之前,我们先来了解一下他的父类:TextReader。对于TextReader,大家可能比较陌生,下面我们来看一下TextReader是什么。
一、TextReader
首先让我们来理解一下什么是TextReader,从字面意思入手的话,大家就会恍然大悟了,一个对于Text的读取器,可是又是怎么读取的呢?聪明的你肯定会想到,当然是通过连续的字符进行读取,为什么在介绍StreamReader之前要介绍这个呢?因为他们两个是父子关系,要了解StreamReader最好先了解他的父亲,下面,简单介绍一下TextReader
1、常用属性和方法:
我们可以想象一下Text这个词,在记事本上,中文、英文、各种代码,等等,都是Text,这些文本归根结底是通过一个个的char组成的,所以微软构造出了TextReader这个抽象类对于读取Text的一系列操作,同样对于TextReader我们无法直接实例化,因为他是一个抽象类,只有定义类的行为,不针对特定实现,那我们来看一下TextReader定义了哪些类的行为:
(1)具有一个protected类型的构造函数
(2)void Close() 方法:和上一篇Stream一样,TextReader也有Close方法,在用完之后,记得主动关闭它
(3)void Dispose()方法:释放所有该TextReader所只有的所有资源(注:加入TextReader中持有Stream或其他对象,当TextReader执行了Dispose方法时,Stream对象也被释放了)
(4)int Peek()方法:这个方法主要是寻找当前char的下一个char,当返回值是-1时,表示下个char已经时最后一个位置的char了。
(5)int Read()方法:同样,Read方法是读取下一个char,但是和Peek方法不同,Read方法使指针只想下个字符,但是Peek方法还是指向原来的那个字符
(6)int Read(char[] buffer,int index,int count)方法:这个重载Read方法和上一篇文章中Stream的Read方法有点神似,区别就是一个参数是byte数组,而这个是char数组,(注:是通过Reader将数据读入buffer数组),index从哪个位置开始,count读取char数量。
(7)int ReadBlock(char[] buffer,int index,int count)方法:和Read方法基本一致,区别是从效率上来说ReadBlock更高点,而且ReadBlock并非属于线程安全,使用时要注意。
(8)virtual string ReadLine()方法:顾名思义,这个方法将读取每一行数据并返回当前行的字符的字符串。
(9)virtual string ReadToEnd()方法:包含从当前位置到TextReader的接微的所有字符的字符串
下面,我们就写几个简单的示例来演示一下上面的几个属性和方法。
1 string text = "abc\nabc"; 2 3 4 using (TextReader reader = new StringReader(text)) 5 { 6 while (reader.Peek() != -1) 7 { 8 Console.WriteLine("Peek = {0}", (char)reader.Peek()); 9 Console.WriteLine("Read = {0}", (char)reader.Read()); 10 } 11 reader.Close(); 12 } 13 14 using (TextReader reader = new StringReader(text)) 15 { 16 char[] charBuffer = new char[3]; 17 int data = reader.ReadBlock(charBuffer, 0, 3); 18 for (int i = 0; i < charBuffer.Length; i++) 19 { 20 Console.WriteLine("通过readBlock读出的数据:{0}", charBuffer[i]); 21 } 22 reader.Close(); 23 } 24 25 using (TextReader reader = new StringReader(text)) 26 { 27 string lineData = reader.ReadLine(); 28 Console.WriteLine("第一行的数据为:{0}", lineData); 29 reader.Close(); 30 } 31 32 using (TextReader reader = new StringReader(text)) 33 { 34 string allData = reader.ReadToEnd(); 35 Console.WriteLine("全部的数据为:{0}", allData); 36 reader.Close(); 37 } 38 39 Console.ReadLine();
输出结果:
二、StreamReader
在说明StreamReader之前,还有一件事要提起,那就是多态,多态到底是什么概念呢?聪明的你肯定会想到多态不就是子类的多种表现形式嘛。不错,但这还是不完全的,不仅如此,现实世界中,父亲帮儿子买房子,但是他没有在房产证上写儿子的名字,所以,这个房子儿子和父亲能共同使用,儿子能根据自己的爱好装修房子,父亲也能在儿子装修好的房子内,也就是说父类能够灵活使用子类的功能,更科学的一点就是子类的指针允许(赋值给)父类指针,上述雷子中,TextReader reader=new StringReader(text) 这个就是个多态的经典例子,大家不妨深刻理解下这个更重要的概念。
1、Encoding编码
为什么要简单介绍Encoding编码呢?因为Encoding编码在Stream和相关类中起的非常重要的作用,由于Encoding类会在后续的博文中详细解释,现在我就先介绍下Encoding类的一些重要的编码。
以上边是Encoding类中一些特定的编码,大家先了解即可,但使用Default时有点必须注意,如果你用的不一样编码的机器的时候,注意服务器或其他操作系统的编码规则,举个例子,如果你在一个中文操作系统中进行编码,但是发布到了一个其他语言的操作系统上,那就会出现问题,这时候,你必须选择一个通用的编码。
2、StreamReader类的定义和作用
StreamReader的定义:实现一个TextReader,使其以以重特定的编码从字节流中读取字节。在对于流的操作中,StreamReader对于流的读取方面非常重要,为什么这么说呢?我们常用的文件的复制、移动、上传、下载、压缩、保存、远程FTP文件的读取、甚至于HttpResponse等等只要是于流相关的任何派生类StreamReader都能够轻松处理,当然,大家甚至可以自定义相关的派生类去实现复杂的序列化。在实际项目中,我们可能碰到过许多上述的情况,有时乱码问题会让我们发狂,但是只要深刻去理解计出的话,我相信大家都能找到适合自己的解决方法。
3、StreamReader类的常用属性和方法
其实StreamReader的一些方法已经在父类TextReader中说的很仔细了,但是个人觉得构造函数和属性高才是重点。
构造函数:
(1)StreamReader(Stream stream):将Stream作为一个参数放入StreamReader,这样的话,StreamReader可以对该Stream进行读取操作,Stream对象可以非常广泛,包括所有Stream的派生类对象。
(2)StreamReader(string string,Encoding encoding):这里的string对象不是简单的字符串,而是文件的地址,然后根据用户选择的编码去读取流中的数据。
(3)StreamReader(string string,bool detectEncodingFromByteOrderMarks):有时候我们希望程序自动判断用何种编码去读取,这时候detectEncodingFromByteOrderMarks这个参数就能起这个作用了,当设置为true的时候,通过查看流的前三个字节来检测编码。如果文件以适当的字节顺序标记开头,该参数自动识别UTF-8、Little-Endian Unicode和Big-Endian Unicode文本,当为false时,方法会去使用用户提供的编码。
(4)StreamReader(string string,Encoding encoding,detectEncodingFromByteOrderMarks,int bufferSize):这个方法提供了4个参数的重载,前3个我们都已经了解,最后一个时缓冲区大小的设置。
StreamReader还有其他的一些构造函数,都是上述4个的扩充,大家可以自己看一下。
4、属性:
(1)BaseStream:大家对于前前一章流的操作应该没什么问题,我就直接企切主题,最简单的理解就是将上述构造函数的流对象在重新取出来进行一系列的操作。
可是如果构造函数中是路径怎么办?一样,构造函数能够将路径文件转化成流对象
1 FileStream fs = new FileStream ( "D:\\TextReader.txt", FileMode.Open , FileAccess.Read ) ; 2 StreamReader sr= new StreamReader ( fs ) ; 3 //本例中的BaseStream就是FileStream 4 sr.BaseStream.Seek (0 , SeekOrigin.Begin ) ;
(2)CurrentEncoding:获取当前StreamReader的Encoding
(3)EndOfStream:判断StreamReader是否已经处于当前流的末尾
好了,下面我们就几个示例来演示一下上述的方法和属性:
1 static void Main(string[] args) 2 { 3 4 //文件地址 5 string txtFilePath="D:\\TextReader.txt"; 6 //定义char数组 7 char[] charBuffer2 = new char[3]; 8 9 //利用FileStream类将文件文本数据变成流然后放入StreamReader构造函数中 10 using(FileStream stream = File.OpenRead(txtFilePath)) 11 { 12 using (StreamReader reader = new StreamReader(stream)) 13 { 14 //StreamReader.Read()方法 15 DisplayResultStringByUsingRead(reader); 16 } 17 } 18 19 using (FileStream stream = File.OpenRead(txtFilePath)) 20 { 21 //使用Encoding.ASCII来尝试下 22 using (StreamReader reader = new StreamReader(stream,Encoding.ASCII,false)) 23 { 24 //StreamReader.ReadBlock()方法 25 DisplayResultStringByUsingReadBlock(reader); 26 } 27 } 28 29 //尝试用文件定位直接得到StreamReader,顺便使用 Encoding.Default 30 using(StreamReader reader = new StreamReader(txtFilePath, Encoding.Default,false,123)) 31 { 32 //StreamReader.ReadLine()方法 33 DisplayResultStringByUsingReadLine(reader); 34 } 35 36 //也可以通过File.OpenText方法直接获取到StreamReader对象 37 using (StreamReader reader = File.OpenText(txtFilePath)) 38 { 39 //StreamReader.ReadLine()方法 40 DisplayResultStringByUsingReadLine(reader); 41 } 42 43 Console.ReadLine(); 44 } 45 46 /// <summary> 47 /// 使用StreamReader.Read()方法 48 /// </summary> 49 /// <param name="reader"></param> 50 public static void DisplayResultStringByUsingRead(StreamReader reader) 51 { 52 int readChar = 0; 53 string result = string.Empty; 54 while ((readChar=reader.Read()) != -1) 55 { 56 result += (char)readChar; 57 } 58 Console.WriteLine("使用StreamReader.Read()方法得到Text文件中的数据为 : {0}", result); 59 } 60 61 /// <summary> 62 /// 使用StreamReader.ReadBlock()方法 63 /// </summary> 64 /// <param name="reader"></param> 65 public static void DisplayResultStringByUsingReadBlock(StreamReader reader) 66 { 67 char[] charBuffer = new char[10]; 68 string result = string.Empty; 69 reader.ReadBlock(charBuffer,0,10); 70 for (int i = 0; i < charBuffer.Length; i++) 71 { 72 result += charBuffer[i]; 73 } 74 Console.WriteLine("使用StreamReader.ReadBlock()方法得到Text文件中前10个数据为 : {0}", result); 75 } 76 77 78 /// <summary> 79 /// 使用StreamReader.ReadLine()方法 80 /// </summary> 81 /// <param name="reader"></param> 82 public static void DisplayResultStringByUsingReadLine(StreamReader reader) 83 { 84 int i=1; 85 string resultString = string.Empty; 86 while ((resultString=reader.ReadLine() )!= null) 87 { 88 Console.WriteLine("使用StreamReader.Read()方法得到Text文件中第{1}行的数据为 : {0}", resultString, i); 89 i++; 90 } 91 92 }
输出结果:
好了,StreamReader的相关知识我们就分享到这里,希望对大家有所帮助。非常感谢 逆时针の风 的博客对我的帮助。