今天我們來簡單的介紹一下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的相關知識我們就分享到這里,希望對大家有所幫助。非常感謝 逆時針の風 的博客對我的幫助。
