C# 温故而知新:Stream篇(六)

C# 温故而知新:Stream篇(

BufferedStream

目录:

  • 简单介绍一下BufferedStream
  • 如何理解缓冲区?
  • BufferedStream的优势
  • 从BufferedStream 中学习装饰模式
  •     如何理解装饰模式
  •     再次理解下装饰模式在Stream中的作用
  •  BufferedStream的构造
  •  BufferedStream的属性
  •  BufferedStream的方法
  •  简单示例:利用socket 读取网页并保存在本地
  •  本章总结

 

 

 

 

1 简单介绍一下BufferedStream

在前几章的讲述中,我们已经能够掌握流的基本特性和特点,一般进行对流的处理时系统肩负着IO所带来的开销,调用十分频繁

这时候就应该想个办法去减少这种开销,而且必须在已有Stream进行扩展,有了以上2点需求,那么我们今天的主题,

BufferedStream闪亮登场了,BufferedStream能够实现流的缓存,换句话说也就是在内存中能够缓存一定的数据而不是

时时给系统带来负担,同时BufferedStream可以对缓存中的数据进行写入或是读取,所以对流的性能带来一定的提升

但是无法同时进行读取或写入工作,如果不使用缓冲区也行,BufferedStream能够保证不用缓冲区时不会降低因缓冲区带来

的读取或写入性能的下降

 

2 如何理解缓冲区

缓冲区是内存中的一块连续区域,用来缓存或临时存储数据,也就是说流可以通过缓冲区逐步对数据进行读取或写入操作,

BufferedStream 中的缓存区可以由用户设定,其表现形式为byte数组,想象下没有缓存区将是很可怕的,假如我们的

非固态硬盘没有缓冲区,如果我们下载速度达到惊人的10m左右,那么下载一个2G或更大的文件时,磁头的读写是非常

的频繁,直接的结果是磁头寿命急剧减少,甚至将硬盘直接烧毁或者损坏

 

3 BufferedStream的优势

理解了缓冲区的重要性后,让我们在来谈下BufferedStream的优势,首先大家肯定觉的疑惑为什么MemoryStream 同样

也是在内存中对流进行操作,和BufferedStream有什么区别呢?BufferedStream并不是将所有内容都存放到内存中

而MemoryStream则是BufferedStream必须跟其他流如FileStream结合使用,而MemoryStream则不用,聪明的你

肯定能够想到,BufferedStream必然类似于一个流的包装类,对流进行”缓存功能的扩展包装”,所以BufferedStream的

优势不仅体现在其原有的缓存功能上,更体现在如何帮助原有类实现其功能的扩展层面上

 

4 从BufferedStream 中简单学习下装饰模式

如何理解装饰模式

             我们在做项目时或者设计项目时常常会碰到这个问题 :我们该如何扩展已有的类功能或者如果扩展一系列派生类的

             功能呢,可能你立刻会想到继承,的确不错,但是如果你仔细看下图并且展开一定的想象的话,你就会发现继承可能

             导致子类的膨胀性增加,如下图所示

           

首先还是得注意以下原则

1. 多用组合,少用继承

利用继承设计子类的行为,是在编译时静态决定的,而且所有的子类都会继承到相同的行为。然而,如果能够利用组合的做法扩展对象的行为,就可以在运行时动态地进行扩展。

2. 类应设计的对扩展开放,对修改关闭。

那么我们该如何避免子类的扩张同时又实现Girl类原有类或派生类的新功能呢?

首先我们要达到2个目的:

1 能够为Girl的所有派生类都实现新功能(不修改派生类的结构)

2 利用对象组合的方式

 

为了满足为Girl 类所有派生类都能使用,那么我们就加上一个Girl的装饰类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);}}

该类继承了Girl类,从而保证了和其他派生类有共同的基本结构,

既然有了这个装饰类,那我们便可以删掉原来的Singing 接口,添加一个

SingingGirlWrapper类来实现对girl的包装类,

    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();}}

           大家不必拘泥于派生的包装类,你完全可以建立一个新的girl包装类来实现特定的功能,上述例子只是演示下派生的包装类
          这样的话,我们便使用了组合的方式实现了既保留原有的接口(或者抽象类),又动态添加了新功能

          

在使用时我们可以将派生类的对象放入装饰类的构造中,这样的话,在执行包装类Decorator方法时,可以执行被包装对象的

Decorator方法和包装类的Decorator方法从而实现对Girl派生类的包装,这样的话就能实现灵活的组合扩展。

static void Main(string[] args){Queen queen = new Queen("Mary","Unite States");SingingGirlWrapper sgw = new SingingGirlWrapper(queen);sgw.Decorator();Console.ReadLine();}


              再次理解下装饰模式在Stream中的作用

通过以上的例子在回到BufferStream章节中,大家肯定一眼就看出了BufferStream其实就是上述例子中的wrapper类

而Stream 类就是其共同的父类,为了给所有的流类提供缓冲功能所以BufferedStream便诞生了,这样的话,我们可以

不用修改其派生类结构,便能灵活组合将缓冲功能嵌入stream中

 

5 BufferedStream的构造

BufferedStream(Stream)

其实BufferedStream的构造主要功能还是设置缓冲区大小,如果没有指定则默认是用4096字节的进行初始化

BufferedStream(Stream, Int32)

第二个参数是手动指定缓冲区大小

第一次使用此构造函数初始化 BufferedStream 对象时分配共享读/写缓冲区。 如果所有的读和写都大于或等于缓冲区大小,则不使用共享缓冲区

 

6 BufferedStream的属性

*1 CanRead 已重写。获取一个值,该值指示当前流是否支持读取。
如果流支持读取,则为 true;如果流已关闭或是通过只写访问方式打开的,则为 false。
如果从 Stream 派生的类不支持读取,则对 StreamReader、StringReader、TextReader 的 Read、ReadByte、BeginRead、EndRead 和 Peek 方法的调用将引发 NotSupportedException。
如果该流已关闭,此属性将返回 false。

 

*2 CanSeek 已重写。获取一个值,该值指示当前流是否支持查找。
如果流支持查找,则为 true;如果流已关闭或者如果流是由操作系统句柄(如管道或到控制台的输出)构造的,则为 false。
如果从 Stream 派生的类不支持查找,则对 Length、SetLength、Position 和 Seek 的调用将引发 NotSupportedException。
如果该流已关闭,此属性将返回 false。

 

*3  CanWrite 已重写。获取一个值,该值指示当前流是否支持写入。
如果流支持写入,则为 true;如果流已关闭或是通过只读访问方式打开的,则为 false。 如果从 Stream 派生的类不支持写入,

则调用 SetLength、Write 或 WriteByte 将引发 NotSupportedException。 如果该流已关闭,此属性将返回 false。

 

*4  Length 已重写。获取流长度,长度以字节为单位。

 

*5  Position 已重写。获取当前流内的位置。

 get 访问器调用 Seek 获取基础流中的当前位置,然后根据缓冲区中的当前位置调整此值

 set 访问器将以前写入缓冲区的所有数据都复制到基础流中,然后调用 Seek

 支持搜索到超出流长度的任何位置。

 

7 BufferedStream的方法

BufferStream的方法基本上和Stream类一致,没有其独特的方法

关于以上方法的注意事项的大家也可参考我的第一篇

 

 简单示例:利用socket 读取网页并保存在本地

    class Program{static void Main(string[] args){Server server = new Server("http://www.163.com/");server.FetchWebPageData();}}public class Server{//端口const int webPort = 80;//默认接收缓存大小byte[] receiveBufferBytes = new byte[4096];//需要获取网页的urlprivate  string webPageURL;public Server(string webPageUrl){webPageURL = webPageUrl;}/// <summary>///  从该网页上获取数据/// </summary>public void FetchWebPageData() {if (!string.IsNullOrEmpty(webPageURL))FetchWebPageData(webPageURL);Console.ReadLine();}/// <summary>/// 从该网页上获取数据/// </summary>/// <param name="webPageURL">网页url</param>private void FetchWebPageData(string webPageURL) {//通过url获取主机信息IPHostEntry iphe = Dns.GetHostEntry(GetHostNameBystrUrl(webPageURL));Console.WriteLine("远程服务器名: {0}", iphe.HostName);//通过主机信息获取其IPIPAddress[] address = iphe.AddressList;IPEndPoint ipep = new IPEndPoint(address[0], 80);//实例化一个socket用于接收网页数据Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//连接
            socket.Connect(ipep);if (socket.Connected){//发送头文件,这样才能下载网页数据socket.Send( Encoding.ASCII.GetBytes( this.GetHeader(webPageURL)));}else { return; }//接收头一批数据var count = socket.Receive(receiveBufferBytes);//转化成string var getString = Encoding.Default.GetString(receiveBufferBytes);//创建文件流FileStream fs = new FileStream(@"d:\\Test.html", FileMode.OpenOrCreate);//创建缓存流BufferedStream bs = new BufferedStream(fs);using (fs){using (bs){byte[] finalContent = Encoding.Default.GetBytes(getString.ToCharArray());//将头一批数据写入本地硬盘bs.Write(finalContent, 0, finalContent.Length);//循环通过socket接收数据while (count > 0){count = socket.Receive(receiveBufferBytes, receiveBufferBytes.Length, SocketFlags.None);//直接将获取到的byte数据写入本地硬盘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">网页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>/// 得到相对路径/// </summary>/// <param name="strUrl">网页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>/// 根据Url得到host/// </summary>/// <param name="strUrl">网页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;}}

本章总结

本章主要讲述了BufferedStream的概念包括缓冲区等等,其中穿插了装饰器模式的简单介绍,希望大家能够BufferedStream有更深的理解,写文不容易,

也请大家多多关注,下一章节将介绍常用的压缩流(非微软类库),谢谢大家支持!

 

转载于:https://www.cnblogs.com/JimmyZheng/archive/2012/04/25/2470277.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/434561.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux内核的Makefile和kconfig解读

一、概述 在内核编译中如何将各个目录树中的文件组织起来编译是一个很重要的问题&#xff0c;并且要根据用户配置来编译特有的内核。为了解决这个问题&#xff0c;内核使用两种文件&#xff0c;Makefie和Kconfig。分布到各目录的Kconfig构成了一个分布式的内核配置数据库&#…

网页快照

C#生成网站网页快照&#xff0c;Html转成图片2012-04-09 22:29HtmlToImg.cs using System; using System.Drawing; using System.Threading; using System.Windows.Forms; /// <summary> /// 生成网页快照 /// </summary> publicclassHtmlToImg { Bitmap m_Bitmap;…

php获取网页输出,PHP 利用AJAX获取网页并输出的实现代码(Zjmainstay)_PHP教程

看点&#xff1a;1、file_get_contents超时控制。2、页面编码判断。3、键盘Enter键捕捉响应。4、键盘event兼容处理。//event event || window.event;5、XMLHttpRequest 和 jQuery 两种实现方案。6、页面及源码同时展示。XMLHttpRequest版本 get_web.php复制代码 代码如下:hea…

HDU 3306 Another kind of Fibonacci

题意&#xff1a;A(0) 1 , A(1) 1 , A(N) X * A(N - 1) Y * A(N - 2) (N > 2)&#xff1b;给定三个值N&#xff0c;X&#xff0c;Y求S(N):S(N) A(0)2 A(1)2……A(n)2。 思路&#xff1a;原来我们讲的斐波那契数列是&#xff1a; F(0) 1, F(1) 1, F(N) F(N - 1) F(N…

php中拼接html代码,如何利用ajax给html动态拼接代码

function get_all_category_with_id() {$.ajax( {type: "get", url: "../../../appUpload/getAllCategoryByid", async : false, dataType: "text", success: function (data) {var obj JSON.parse(data);var str "";//先将元素对应清…

Arm Linux交叉编译和连接过程分析(1)

一、配置内核&#xff08;Kconfig&#xff09; 我们配置内核是实质是根据众多目录下面的Kconfig文件中组合成我们需要的一个最佳选择&#xff0c;即最终在根目录下面生成的.config文件&#xff0c;而这个文件会在根目录Makefile下调用的。这一部分我们主要讨论整个SEP4020体系…

struts2标签_select获取action传过来的值

<s:select list"#session.userlist" //从Action传过来的键(属性)的名称headerKey"请选择" //默认选中项的值headerValue"请选择" //默认选中项显示的信息listKey"project_id" …

3500 yuan to php,350 CNY to PHP Currency Converter - 人民币 菲律宾比索 汇率兑换

Exchange350 CNY2612.29 PHPExchange 350 人民币2612.29 菲律宾比索Exchange1750 CNY13061.46 PHPExchange 1750 人民币13061.46 菲律宾比索Exchange3500 CNY26122.92 PHPExchange 3500 人民币26122.92 菲律宾比索Exchange17500 CNY130614.62 PHPExchange 17500 人民币130614.6…

Arm Linux交叉编译和连接过程分析(2)

二、编译内核镜像过程 1、编译过程中涉及到到文件&#xff1a; /Makefile 编译产生顶层vmlinux镜像文件/scripts/Kbuild.include make过程中到一些基本定义 /scripts/Makefile.lib 编译内核时用到到函数库文件 /scripts/Makefile.build 内核编译到相关命令文件…

sipxecs简介

SipX和SipExchange的代码于2007年合并成SipXecs&#xff0c;北电和NTT等大公司参与构建SipXecs架构。SipXecs是电信级的&#xff0c;针对统一通信UC和呼叫中心Call Center应用&#xff0c;另外&#xff0c;支持设备批量升级&#xff0c;批量配置管理等应用&#xff0c;网管支持…

ASP.NET数据格式的Format-- DataFormatString

我们在呈现数据的时候&#xff0c;不要将未经修饰过的数据呈现给使用者。例如金额一万元&#xff0c;如果我们直接显示「10000」&#xff0c;可能会导致使用者看成一千或十万&#xff0c;造成使用者阅读数据上的困扰。若我们将一万元润饰后输出为「NT$10,000」&#xff0c;不但…

fortran转换 matlab代码,将Fortran77代码转换为Matlab代码以查找特征值/向量

我将Fortran 77中的书面代码转换为Matlab代码。该函数使用QL算法计算矩阵的特征值和特征向量。由于某些原因&#xff0c;我不能在matlab中使用eig函数的结果。这种方法得到的特征值与eig函数得到的特征值不一样&#xff0c;有些相同但有些不同。我不知道问题在哪里。感谢您的任…

linux内核中分配4M以上大内存的方法

在内核中, kmalloc能够分配的最大连续内存为2的(MAX_ORDER-1)次方个page(参见alloc_pages函数, "if (unlikely(order > MAX_ORDER)) return NULL;"), page的大小一般是4K bytes,MAX_ORDER缺省定义为11, 所以如果不修改内核, kmalloc能够分配的最大连续…

sql server 2008学习3 表组织和索引组织

表组织 表包含在一个或多个分区中&#xff0c;每个分区在一个堆或一个聚集索引结构包含数据行。堆页或聚集索引页在一个或多个分配单元中进行管理&#xff0c;具体的分配单元数取决于数据行中的列类型。 聚集表、堆和索引 SQL Server 表使用下列两种方法之一来组织其分区中的数…

BootLoader与Linux内核的参数传递

在嵌入式系统中&#xff0c;BootLoader 是用来初始化硬件&#xff0c;加载内核&#xff0c;传递参数。因为嵌入式系统的硬件环境各不相同&#xff0c;所以嵌入式系统的BootLoader 也各不相同&#xff0c;其中比较通用的是U-Boot&#xff0c;它支持不同的体系结构&#xff0c;如…

怎么跟踪php代码,第九节 PHP 跟踪调试代码 XDebug

>[success] # PHP 跟踪调试代码 XDebug- [下载XDebug扩展](https://xdebug.org/download.php)- 下载对应PHP版本的Xdebug![](https://box.kancloud.cn/c17f1f1e965522c2fe1411e1759e4447_870x524.png)- 线程安全(TS)和非线程安全(NTS)![](https://box.kancloud.cn/24efc18d4…

oracle经纬度换算成xy坐标,经纬度换算成xy坐标(经纬度转换xy坐标算法)

经纬度怎么转换成平面xy坐标&#xff1f;这里面的经纬度转换成xy坐标是多少&#xff1f;求解你把角度的单位设成度分秒制输入不久可以了。具体输入units命令&#xff0c;对话框中会有一个角度的单位制选择&#xff0c;包括度分秒制。例如绘制一条与当前点距离为100&#xff0c;…

Linux内核参数传递Tag

在2.4&#xff08;具体哪个版本记不清了&#xff09;以后的Linux内核中引入了一种新的向内核传递参数的方法tag标记。内核参数通过一个静态的tag链表在启动的时候传递到内核。每个tag的结构为 ----------- tag_header ----------- tag_xxx ----------- 其中tag_header为tag头&a…

ns学习资料

&#xff08;一&#xff09;. NS常用基本网站   1. Maillist个人觉得是寻求问题答案最好的地方。   http://mailman.isi.edu/pipermail/ns-users/   2. 柯老师的网站&#xff0c;包含很多非常实用资源&#xff1a;安装&#xff0c;trace文件分析&#xff0c;源代码分析&a…

Oracle备份standby,Oracle 11g 利用泠备份恢复standby库

Oracle 11g 利用泠备份恢复standby库1 开始在备库上进行泠备份先查好控制文件、redo、undo文件、数据文件的路径1.1 先关闭主库的归档日志传输SQL> ALTER system SETlog_archive_dest_state_2 DEFER;System altered.SQL>1.2 先关闭standby库SQL> shutdown immediate;D…