C# 温故而知新:Stream篇(六)
C# 溫故而知新:Stream篇(六)
BufferedStream
目錄:
- 簡(jiǎn)單介紹一下BufferedStream
- 如何理解緩沖區(qū)?
- BufferedStream的優(yōu)勢(shì)
- 從BufferedStream 中學(xué)習(xí)裝飾模式
- 如何理解裝飾模式
- 再次理解下裝飾模式在Stream中的作用
- ?BufferedStream的構(gòu)造
- ?BufferedStream的屬性
- ?BufferedStream的方法
- ?簡(jiǎn)單示例:利用socket 讀取網(wǎng)頁(yè)并保存在本地
- ?本章總結(jié)
?
?
?
?
1 簡(jiǎn)單介紹一下BufferedStream
在前幾章的講述中,我們已經(jīng)能夠掌握流的基本特性和特點(diǎn),一般進(jìn)行對(duì)流的處理時(shí)系統(tǒng)肩負(fù)著IO所帶來(lái)的開(kāi)銷(xiāo),調(diào)用十分頻繁,
這時(shí)候就應(yīng)該想個(gè)辦法去減少這種開(kāi)銷(xiāo),而且必須在已有Stream進(jìn)行擴(kuò)展,有了以上2點(diǎn)需求,那么我們今天的主題,
BufferedStream閃亮登場(chǎng)了,BufferedStream能夠?qū)崿F(xiàn)流的緩存,換句話說(shuō)也就是在內(nèi)存中能夠緩存一定的數(shù)據(jù)而不是
時(shí)時(shí)給系統(tǒng)帶來(lái)負(fù)擔(dān),同時(shí)BufferedStream可以對(duì)緩存中的數(shù)據(jù)進(jìn)行寫(xiě)入或是讀取,所以對(duì)流的性能帶來(lái)一定的提升,
但是無(wú)法同時(shí)進(jìn)行讀取或?qū)懭牍ぷ?/span>,如果不使用緩沖區(qū)也行,BufferedStream能夠保證不用緩沖區(qū)時(shí)不會(huì)降低因緩沖區(qū)帶來(lái)
的讀取或?qū)懭胄阅艿南陆?/span>
?
2?如何理解緩沖區(qū)
緩沖區(qū)是內(nèi)存中的一塊連續(xù)區(qū)域,用來(lái)緩存或臨時(shí)存儲(chǔ)數(shù)據(jù),也就是說(shuō)流可以通過(guò)緩沖區(qū)逐步對(duì)數(shù)據(jù)進(jìn)行讀取或?qū)懭氩僮?#xff0c;
BufferedStream 中的緩存區(qū)可以由用戶(hù)設(shè)定,其表現(xiàn)形式為byte數(shù)組,想象下沒(méi)有緩存區(qū)將是很可怕的,假如我們的
非固態(tài)硬盤(pán)沒(méi)有緩沖區(qū),如果我們下載速度達(dá)到驚人的10m左右,那么下載一個(gè)2G或更大的文件時(shí),磁頭的讀寫(xiě)是非常
的頻繁,直接的結(jié)果是磁頭壽命急劇減少,甚至將硬盤(pán)直接燒毀或者損壞
?
3 BufferedStream的優(yōu)勢(shì)
理解了緩沖區(qū)的重要性后,讓我們?cè)趤?lái)談下BufferedStream的優(yōu)勢(shì),首先大家肯定覺(jué)的疑惑為什么MemoryStream 同樣
也是在內(nèi)存中對(duì)流進(jìn)行操作,和BufferedStream有什么區(qū)別呢?BufferedStream并不是將所有內(nèi)容都存放到內(nèi)存中,
而MemoryStream則是。BufferedStream必須跟其他流如FileStream結(jié)合使用,而MemoryStream則不用,聰明的你
肯定能夠想到,BufferedStream必然類(lèi)似于一個(gè)流的包裝類(lèi),對(duì)流進(jìn)行”緩存功能的擴(kuò)展包裝”,所以BufferedStream的
優(yōu)勢(shì)不僅體現(xiàn)在其原有的緩存功能上,更體現(xiàn)在如何幫助原有類(lèi)實(shí)現(xiàn)其功能的擴(kuò)展層面上
?
4 從BufferedStream 中簡(jiǎn)單學(xué)習(xí)下裝飾模式
如何理解裝飾模式
???????????? 我們?cè)谧鲰?xiàng)目時(shí)或者設(shè)計(jì)項(xiàng)目時(shí)常常會(huì)碰到這個(gè)問(wèn)題 :我們?cè)撊绾螖U(kuò)展已有的類(lèi)功能或者如果擴(kuò)展一系列派生類(lèi)的
???????????? 功能呢,可能你立刻會(huì)想到繼承,的確不錯(cuò),但是如果你仔細(xì)看下圖并且展開(kāi)一定的想象的話,你就會(huì)發(fā)現(xiàn)繼承可能
???????????? 導(dǎo)致子類(lèi)的膨脹性增加,如下圖所示
???????????
首先還是得注意以下原則:
1. 多用組合,少用繼承。
利用繼承設(shè)計(jì)子類(lèi)的行為,是在編譯時(shí)靜態(tài)決定的,而且所有的子類(lèi)都會(huì)繼承到相同的行為。然而,如果能夠利用組合的做法擴(kuò)展對(duì)象的行為,就可以在運(yùn)行時(shí)動(dòng)態(tài)地進(jìn)行擴(kuò)展。
2. 類(lèi)應(yīng)設(shè)計(jì)的對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉。
那么我們?cè)撊绾伪苊庾宇?lèi)的擴(kuò)張同時(shí)又實(shí)現(xiàn)Girl類(lèi)原有類(lèi)或派生類(lèi)的新功能呢?
首先我們要達(dá)到2個(gè)目的:
1 能夠?yàn)镚irl的所有派生類(lèi)都實(shí)現(xiàn)新功能(不修改派生類(lèi)的結(jié)構(gòu))
2 利用對(duì)象組合的方式
?
為了滿(mǎn)足為Girl 類(lèi)所有派生類(lèi)都能使用,那么我們就加上一個(gè)Girl的裝飾類(lèi)GirlWrapper:
public abstract class GirlWrapper : Girl{protected Girl girl;public GirlWrapper(Girl thisGril){this.girl = thisGril;}public override void Decrorator(){girl.Decrorator();}public override string ToString(){return string.Format("{0}:{1}", this.girl.GirlName, this.girl.Nation);}}該類(lèi)繼承了Girl類(lèi),從而保證了和其他派生類(lèi)有共同的基本結(jié)構(gòu),
既然有了這個(gè)裝飾類(lèi),那我們便可以刪掉原來(lái)的Singing 接口,添加一個(gè)
SingingGirlWrapper類(lèi)來(lái)實(shí)現(xiàn)對(duì)girl的包裝類(lèi),
public class SingingGirlWrapper : GirlWrapper{public SingingGirlWrapper(Girl thisGril): base(thisGril){}public void Decorator() {Console.WriteLine("SingingGirlWrapper decorateor:The girl named {0} who from {1} is {2} can singing nao", this.GirlName, this.Nation, this.girl.GetType().Name);base.Decrorator();}public override string ToString(){return base.ToString();}}?????????? 大家不必拘泥于派生的包裝類(lèi),你完全可以建立一個(gè)新的girl包裝類(lèi)來(lái)實(shí)現(xiàn)特定的功能,上述例子只是演示下派生的包裝類(lèi)
??????????這樣的話,我們便使用了組合的方式實(shí)現(xiàn)了既保留原有的接口(或者抽象類(lèi)),又動(dòng)態(tài)添加了新功能
??????????
在使用時(shí)我們可以將派生類(lèi)的對(duì)象放入裝飾類(lèi)的構(gòu)造中,這樣的話,在執(zhí)行包裝類(lèi)Decorator方法時(shí),可以執(zhí)行被包裝對(duì)象的
Decorator方法和包裝類(lèi)的Decorator方法從而實(shí)現(xiàn)對(duì)Girl派生類(lèi)的包裝,這樣的話就能實(shí)現(xiàn)靈活的組合擴(kuò)展。
static void Main(string[] args){Queen queen = new Queen("Mary","Unite States");SingingGirlWrapper sgw = new SingingGirlWrapper(queen);sgw.Decorator();Console.ReadLine();}
??????????????再次理解下裝飾模式在Stream中的作用
通過(guò)以上的例子在回到BufferStream章節(jié)中,大家肯定一眼就看出了BufferStream其實(shí)就是上述例子中的wrapper類(lèi),
而Stream 類(lèi)就是其共同的父類(lèi),為了給所有的流類(lèi)提供緩沖功能所以BufferedStream便誕生了,這樣的話,我們可以
不用修改其派生類(lèi)結(jié)構(gòu),便能靈活組合將緩沖功能嵌入stream中
?
5 BufferedStream的構(gòu)造
BufferedStream(Stream)
其實(shí)BufferedStream的構(gòu)造主要功能還是設(shè)置緩沖區(qū)大小,如果沒(méi)有指定則默認(rèn)是用4096字節(jié)的進(jìn)行初始化
BufferedStream(Stream, Int32)
第二個(gè)參數(shù)是手動(dòng)指定緩沖區(qū)大小
第一次使用此構(gòu)造函數(shù)初始化 BufferedStream 對(duì)象時(shí)分配共享讀/寫(xiě)緩沖區(qū)。 如果所有的讀和寫(xiě)都大于或等于緩沖區(qū)大小,則不使用共享緩沖區(qū)。
?
6 BufferedStream的屬性
*1 CanRead 已重寫(xiě)。獲取一個(gè)值,該值指示當(dāng)前流是否支持讀取。
如果流支持讀取,則為 true;如果流已關(guān)閉或是通過(guò)只寫(xiě)訪問(wèn)方式打開(kāi)的,則為 false。
如果從 Stream 派生的類(lèi)不支持讀取,則對(duì) StreamReader、StringReader、TextReader 的 Read、ReadByte、BeginRead、EndRead 和 Peek 方法的調(diào)用將引發(fā) NotSupportedException。
如果該流已關(guān)閉,此屬性將返回 false。
?
*2 CanSeek 已重寫(xiě)。獲取一個(gè)值,該值指示當(dāng)前流是否支持查找。
如果流支持查找,則為 true;如果流已關(guān)閉或者如果流是由操作系統(tǒng)句柄(如管道或到控制臺(tái)的輸出)構(gòu)造的,則為 false。
如果從 Stream 派生的類(lèi)不支持查找,則對(duì) Length、SetLength、Position 和 Seek 的調(diào)用將引發(fā) NotSupportedException。
如果該流已關(guān)閉,此屬性將返回 false。
?
*3? CanWrite 已重寫(xiě)。獲取一個(gè)值,該值指示當(dāng)前流是否支持寫(xiě)入。
如果流支持寫(xiě)入,則為 true;如果流已關(guān)閉或是通過(guò)只讀訪問(wèn)方式打開(kāi)的,則為 false。 如果從 Stream 派生的類(lèi)不支持寫(xiě)入,
則調(diào)用 SetLength、Write 或 WriteByte 將引發(fā) NotSupportedException。 如果該流已關(guān)閉,此屬性將返回 false。
?
*4 ?Length 已重寫(xiě)。獲取流長(zhǎng)度,長(zhǎng)度以字節(jié)為單位。
?
*5? Position 已重寫(xiě)。獲取當(dāng)前流內(nèi)的位置。
?get 訪問(wèn)器調(diào)用 Seek 獲取基礎(chǔ)流中的當(dāng)前位置,然后根據(jù)緩沖區(qū)中的當(dāng)前位置調(diào)整此值。
?set 訪問(wèn)器將以前寫(xiě)入緩沖區(qū)的所有數(shù)據(jù)都復(fù)制到基礎(chǔ)流中,然后調(diào)用 Seek。
?支持搜索到超出流長(zhǎng)度的任何位置。
?
7 BufferedStream的方法
BufferStream的方法基本上和Stream類(lèi)一致,沒(méi)有其獨(dú)特的方法
關(guān)于以上方法的注意事項(xiàng)的大家也可參考我的第一篇
?
8??簡(jiǎn)單示例:利用socket 讀取網(wǎng)頁(yè)并保存在本地
class Program{static void Main(string[] args){Server server = new Server("http://www.163.com/");server.FetchWebPageData();}}public class Server{//端口const int webPort = 80;//默認(rèn)接收緩存大小byte[] receiveBufferBytes = new byte[4096];//需要獲取網(wǎng)頁(yè)的urlprivate string webPageURL;public Server(string webPageUrl){webPageURL = webPageUrl;}/// <summary>/// 從該網(wǎng)頁(yè)上獲取數(shù)據(jù)/// </summary>public void FetchWebPageData() {if (!string.IsNullOrEmpty(webPageURL))FetchWebPageData(webPageURL);Console.ReadLine();}/// <summary>/// 從該網(wǎng)頁(yè)上獲取數(shù)據(jù)/// </summary>/// <param name="webPageURL">網(wǎng)頁(yè)url</param>private void FetchWebPageData(string webPageURL) {//通過(guò)url獲取主機(jī)信息IPHostEntry iphe = Dns.GetHostEntry(GetHostNameBystrUrl(webPageURL));Console.WriteLine("遠(yuǎn)程服務(wù)器名: {0}", iphe.HostName);//通過(guò)主機(jī)信息獲取其IPIPAddress[] address = iphe.AddressList;IPEndPoint ipep = new IPEndPoint(address[0], 80);//實(shí)例化一個(gè)socket用于接收網(wǎng)頁(yè)數(shù)據(jù)Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//連接 socket.Connect(ipep);if (socket.Connected){//發(fā)送頭文件,這樣才能下載網(wǎng)頁(yè)數(shù)據(jù)socket.Send( Encoding.ASCII.GetBytes( this.GetHeader(webPageURL)));}else { return; }//接收頭一批數(shù)據(jù)var count = socket.Receive(receiveBufferBytes);//轉(zhuǎn)化成string var getString = Encoding.Default.GetString(receiveBufferBytes);//創(chuàng)建文件流FileStream fs = new FileStream(@"d:\\Test.html", FileMode.OpenOrCreate);//創(chuàng)建緩存流BufferedStream bs = new BufferedStream(fs);using (fs){using (bs){byte[] finalContent = Encoding.Default.GetBytes(getString.ToCharArray());//將頭一批數(shù)據(jù)寫(xiě)入本地硬盤(pán)bs.Write(finalContent, 0, finalContent.Length);//循環(huán)通過(guò)socket接收數(shù)據(jù)while (count > 0){count = socket.Receive(receiveBufferBytes, receiveBufferBytes.Length, SocketFlags.None);//直接將獲取到的byte數(shù)據(jù)寫(xiě)入本地硬盤(pán)bs.Write(receiveBufferBytes, 0, receiveBufferBytes.Length);Console.WriteLine(Encoding.Default.GetString(receiveBufferBytes));}bs.Flush();fs.Flush();bs.Close();fs.Close();}}}/// <summary>/// 得到header/// </summary>/// <param name="url">網(wǎng)頁(yè)url</param>/// <returns>header字符串</returns>private string GetHeader(string webPageurl) {return "GET " + GetRelativeUrlBystrUrl(webPageurl) + " HTTP/1.1\r\nHost: "+ GetHostNameBystrUrl(webPageurl) + "\r\nConnection: Close\r\n\r\n";}/// <summary>/// 得到相對(duì)路徑/// </summary>/// <param name="strUrl">網(wǎng)頁(yè)url</param>/// <returns></returns>private string GetRelativeUrlBystrUrl(string strUrl){int iIndex = strUrl.IndexOf(@"//");if (iIndex <= 0)return "/";string strTemp = strUrl.Substring(iIndex + 2);iIndex = strTemp.IndexOf(@"/");if (iIndex > 0)return strTemp.Substring(iIndex);elsereturn "/";}/// <summary>/// 根據(jù)Url得到host/// </summary>/// <param name="strUrl">網(wǎng)頁(yè)url</param>/// <returns></returns>private string GetHostNameBystrUrl(string strUrl){int iIndex = strUrl.IndexOf(@"//");if (iIndex <= 0)return "";string strTemp = strUrl.Substring(iIndex + 2);iIndex = strTemp.IndexOf(@"/");if (iIndex > 0)return strTemp.Substring(0, iIndex);elsereturn strTemp;}}本章總結(jié)
本章主要講述了BufferedStream的概念包括緩沖區(qū)等等,其中穿插了裝飾器模式的簡(jiǎn)單介紹,希望大家能夠BufferedStream有更深的理解,寫(xiě)文不容易,
也請(qǐng)大家多多關(guān)注,下一章節(jié)將介紹常用的壓縮流(非微軟類(lèi)庫(kù)),謝謝大家支持!
?
轉(zhuǎn)載于:https://www.cnblogs.com/JimmyZheng/archive/2012/04/25/2470277.html
總結(jié)
以上是生活随笔為你收集整理的C# 温故而知新:Stream篇(六)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Eclipse设置字体大小
- 下一篇: [轉]C# 中的委托和事件