(轉)C# 溫故而知新:Stream篇(二)

(本文轉自)http://www.cnblogs.com/JimmyZheng/archive/2012/03/19/2405216.html

C# 溫故而知新:Stream篇(二)

TextReader 和StreamReader

目錄:

爲什麼要介紹 TextReader?

TextReader的常用屬性和方法

TextReader 示例

從StreamReader想到多態

簡單介紹下Encoding 編碼

StreamReader 的定義及作用

StreamReader 類的常用方法屬性

StreamReader示例

本章總結

 

 

 

爲什麼要介紹 TextReader?

首先讓我們來理解下什麼是TextReader,從字面上的意思入手的話,大家就會恍然大悟了

一個對於Text的讀取器,可是又是怎麼讀取的呢?聰明的你肯定會想到,當然是通過連續

的字符進行讀取, 爲什麼在介紹StreamReader之前,要搞這個東東? 答案其實很簡單:他們

兩個就是父子關係,要了解StreamReader最好先了解他的父親,請允許我對他們進行下簡單介紹: 

 

TextReader的常用屬性和方法:

我們閉上眼可以想象一下 Text這個詞的範圍,它囊括了許多的文件類型,我們可以在記事本上

使用任何語言(英語,中文,c# ,天書,javascript,jquery,xml,xaml,sql,c++……),如此多

的語言文本歸根結底還是通過一個個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 的結尾的所有字符的字符串 

 

下面的例子將是對上述方法的溫故而知新:

複製代碼
 string text = "abc\nabc";


using (TextReader reader = new StringReader(text))
{
while (reader.Peek() != -1)
{
Console.WriteLine("Peek = {0}", (char)reader.Peek());
Console.WriteLine("Read = {0}", (char)reader.Read());
}
reader.Close();
}

using (TextReader reader = new StringReader(text))
{
char[] charBuffer = new char[3];
int data = reader.ReadBlock(charBuffer, 0, 3);
for (int i = 0; i < charBuffer.Length; i++)
{
Console.WriteLine("通過readBlock讀出的數據:{0}", charBuffer[i]);
}
reader.Close();
}

using (TextReader reader = new StringReader(text))
{
string lineData = reader.ReadLine();
Console.WriteLine("第一行的數據爲:{0}", lineData);
reader.Close();
}

using (TextReader reader = new StringReader(text))
{
string allData = reader.ReadToEnd();
Console.WriteLine("全部的數據爲:{0}", allData);
reader.Close();
}

Console.ReadLine();
複製代碼

輸出結果:

 

StreamReader登場

終於今天的主角登場了,在前面做了那麼多鋪墊後在學習它會事半功倍

 

從StreamReader想到多態

在說明StreamReader之前還有一件事要提起,那就是多態, 多態到底是什麼概念呢?聰明的你肯定會想到多態不就是子類的多種

表現形式?不錯,但這還是不是完全的,不僅如此,現實世界中,父親幫兒子買了套房子,但是他沒有在房產證上寫兒子的名字,

所以這個房子兒子和父親能共同使用,兒子能根據自己的愛好裝修房子,父親也能住在兒子裝修好的房子內,也就是說父類能夠

靈活使用子類的功能,更科學的一點就是子類的指針允許(賦值給)父類指針。上述例子中

TextReader reader = new StringReader(text)

 這個就是個多態的經典例子大家不妨深刻理解下這個重要的概念

 

簡單介紹下Encoding編碼

爲什麼要簡單介紹Encoding編碼?因爲Encoding編碼在Stream和相關類中起的非常重要的作用,

由於Encoding類會在後續章節詳細解釋,現在我就先介紹下 Encoding類一些重要編碼  

 

以上便是Encoding類中一些特定的編碼,大家先了解即可,但使用Default時有點必須注意,如果你用不一樣編碼的機器的時候,

注意服務器或者其他操作系統的編碼規則,舉個例子,如果你在一箇中文操作系統進行編碼,但是發佈到了一個其他語言的操作

系統上那就會出問題了這時候你必須選擇一個通用編碼

StreamReader 類的定義和作用

StreamReader 的定義:實現一個 TextReader,使其以一種特定的編碼從字節流中讀取字符

在對於流的操作中,StreamReader對於流的讀取方面非常重要,爲什麼這麼說呢,我們常用的文件的複製,移動,上傳,下載,壓縮,保存,

遠程FTP文件的讀取,甚至於HttpResponse等等只要是於流相關的任何派生類StreamReader 都能夠輕鬆處理,當然,大家甚至可以自定義

相關的派生類去實現複雜的序列化。在實際項目,我們可能碰到過許多上述的情況,有時亂碼的問題會讓我們發狂,但是隻要深刻去理解基礎的話,

我相信大家都能找到適合自己的解決方法

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, bool detectEncodingFromByteOrderMarks,int bufferSize)          

這個放提供了4個參數的重載,前3個我們都已經瞭解,最後個是緩衝區大小的設置,

*StreamReader 還有其他的一些構造函數,都是上述4個的擴充,所以本例就取上述的4個構造函數來說明 

屬性:

1:BaseStream

  大家對於前一章流的操作應該沒什麼問題,我就直切主題,最簡單的理解就是將上述構造函數的流對象在重新取出來進行一系列的操作

  可是如果構造函數中是路徑怎麼辦,一樣,構造函數能夠將路徑文件轉化成流對象

FileStream fs = new FileStream ( "D:\\TextReader.txt", FileMode.Open , FileAccess.Read ) ; 
StreamReader sr= new StreamReader ( fs ) ;
//本例中的BaseStream就是FileStream
sr.BaseStream.Seek (0 , SeekOrigin.Begin ) ;
 

 2:CurrentEncoding:

獲取當前StreamReader的Encoding

3:EndOfStream:

判斷StreamReader是否已經處於當前流的末尾

 

 

最後用FileStream的示例來溫故下StreamReader

複製代碼
static void Main(string[] args)
{

//文件地址
string txtFilePath="D:\\TextReader.txt";
//定義char數組
char[] charBuffer2 = new char[3];

//利用FileStream類將文件文本數據變成流然後放入StreamReader構造函數中
using(FileStream stream = File.OpenRead(txtFilePath))
{
using (StreamReader reader = new StreamReader(stream))
{
//StreamReader.Read()方法
DisplayResultStringByUsingRead(reader);
}
}

using (FileStream stream = File.OpenRead(txtFilePath))
{
//使用Encoding.ASCII來嘗試下
using (StreamReader reader = new StreamReader(stream,Encoding.ASCII,false))
{
//StreamReader.ReadBlock()方法
DisplayResultStringByUsingReadBlock(reader);
}
}

//嘗試用文件定位直接得到StreamReader,順便使用 Encoding.Default
using(StreamReader reader = new StreamReader(txtFilePath, Encoding.Default,false,123))
{
//StreamReader.ReadLine()方法
DisplayResultStringByUsingReadLine(reader);
}

//也可以通過File.OpenText方法直接獲取到StreamReader對象
using (StreamReader reader = File.OpenText(txtFilePath))
{
//StreamReader.ReadLine()方法
DisplayResultStringByUsingReadLine(reader);
}

Console.ReadLine();
}

/// <summary>
/// 使用StreamReader.Read()方法
/// </summary>
/// <param name="reader"></param>
public static void DisplayResultStringByUsingRead(StreamReader reader)
{
int readChar = 0;
string result = string.Empty;
while ((readChar=reader.Read()) != -1)
{
result += (char)readChar;
}
Console.WriteLine("使用StreamReader.Read()方法得到Text文件中的數據爲 : {0}", result);
}

/// <summary>
/// 使用StreamReader.ReadBlock()方法
/// </summary>
/// <param name="reader"></param>
public static void DisplayResultStringByUsingReadBlock(StreamReader reader)
{
char[] charBuffer = new char[10];
string result = string.Empty;
reader.ReadBlock(charBuffer,0,10);
for (int i = 0; i < charBuffer.Length; i++)
{
result += charBuffer[i];
}
Console.WriteLine("使用StreamReader.ReadBlock()方法得到Text文件中前10個數據爲 : {0}", result);
}


/// <summary>
/// 使用StreamReader.ReadLine()方法
/// </summary>
/// <param name="reader"></param>
public static void DisplayResultStringByUsingReadLine(StreamReader reader)
{
int i=1;
string resultString = string.Empty;
while ((resultString=reader.ReadLine() )!= null)
{
Console.WriteLine("使用StreamReader.Read()方法得到Text文件中第{1}行的數據爲 : {0}", resultString, i);
i++;
}

}
複製代碼

 輸出結果:

 

本章總結

本章詳細介紹了TextReader和StreamReader的定義概念和一些注意事項,希望大家能夠在本文中溫故而知新,下章會簡單介紹下TextWriter和StreamWriter

敬請期待!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章