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,一经查实,立即删除!

相关文章

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…

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

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

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

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

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

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

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…

matlab单位阶跃响应与单位脉冲响应,python 已知响应函数求单位阶跃响应或脉冲响应...

最近学习自动控制原理&#xff0c;关于控制系统的一些&#xff0c;老师用布置了一些作业说要用matlab画&#xff0c;我试试python首先介绍一下所使用的库&#xff1a;control matplotlib sympy1.control库&#xff1a;用来计算脉冲响应与阶跃响应Paste_Image.png2.sympy&#x…

$_server['php_self'] 漏洞,Discuz! $_SERVER['PHP_SELF'] XSS Vulnerability

在common.inc.php文件的69行&#xff1a;$PHP_SELF $_SERVER[PHP_SELF] ? $_SERVER[PHP_SELF] : $_SERVER[SCRIPT_NAME];$SCRIPT_FILENAME str_replace(\\\\, /, (isset($_SERVER[PATH_TRANSLATED]) ? $_SERVER[PATH_TRANSLATED] : $_SERVER[SCRIPT_FILENAME]));$boardurl …

【前端破解系列之一】一分钟教你破解下载虾米音乐

虾米音乐网站上有很多高品质的音乐和精心组织的精选集&#xff0c;但普通用户只能试听&#xff0c;不能下载&#xff0c;下载的话需要使用“米”&#xff0c;这个“米”除了极少数的新手任务可以获得之外&#xff0c;基本上都要靠付费来购买&#xff0c;很多人没有网银或者没有…

网络编程常用接口的内核实现----sys_listen()

listen()函数仅在TCP服务器端调用&#xff0c;它做两个事情&#xff1a;将套接字转换到LISTEN状态和设置套接上的最大连接队列。listen()对应的内核实现为sys_listen()&#xff0c;下面开始对其实现作具体的分析。 一、sys_listen()函数 sys_listen()的源码实现及分析如下所示…

linux查看启动配置文件内容,Linux开机启动项的查看和设置方法总结

一、查看开机自启项1.Centos7自启项查看方式从Centos6的chkconfig改为&#xff1a;systemctl list-unit-files2.用grep过滤查看&#xff0c;比如&#xff1a;查看启动项&#xff1a;systemctl list-unit-files | grep enable查看sshd服务自启动情况&#xff1a;systemctl list-…

XP Embedded:不同的用户使用不同的外壳程序

摘要&#xff1a; 能够使应用程序成为外壳程序是 Windows XP Embedded 的关键功能之一。设备可以在自定义外壳程序而不是 Explorer 外壳程序中启动&#xff0c;这提供了两个好处。第一个好处是系统能够更快地启动。Explorer 外壳程序需要花费大量的时间来加载所有支持库和文件…

linux系统中 库分为静态库和,Linux系统中“动态库”和“静态库”那点事儿-【经典好文】...

今天我们主要来说说Linux系统下基于动态库(.so)和静态(.a)的程序那些猫腻。在这之前&#xff0c;我们需要了解一下源代码到可执行程序之间到底发生了什么神奇而美妙的事情。在linux操作系统中&#xff0c;普遍使用ELF格式作为可执行程序或者程序生成过程中的中间格式。ELF(Exec…

linux上的壁纸软件下载,Ubuntu 17.10上安装开源壁纸工具Wallch 4.0

在Ubuntu 17.04上安装WallchWallch是一款免费的开源通用壁纸更换器&#xff0c;用户可以在设置的时间更改桌面背景图片。它会在桌面上更改并显示随机图片或维基百科的当天图片。它还具有一个实时地球Living Earth壁纸&#xff0c;每30分钟更换桌面背景&#xff0c;以显示阳光和…

linux find显示文件的基本信息,命令find搜索文件,命令stat查看文件的详细信息

命令stat命令语法stat(选项)(参数)命令描述命令stat用于显示文件的状态信息。stat命令的输出信息比ls命令的输出信息要更详细。命令选项-L&#xff1a;支持符号连接&#xff1b;-f&#xff1a;显示文件系统状态而非文件状态&#xff1b;-t&#xff1a;以简洁方式输出信息&#…

Linux rpm 命令参数使用详解[介绍和应用]

RPM是RedHat Package Manager&#xff08;RedHat软件包管理工具&#xff09;类似Windows里面的“添加/删除程序” rpm 执行安装包 二进制包&#xff08;Binary&#xff09;以及源代码包&#xff08;Source&#xff09;两种。二进制包可以直接安装在计算机中&#xff0c;而源代…

Ubuntu10.10的网络配置

有一阵子着实对Ubuntu的网络配置很迷惑&#xff0c;耐下心来仔细上网找了找&#xff0c;有点小心得&#xff0c;总结一下。 先说下大概的配置过程&#xff0c;再去细究一些情况。 一、配置大概分三类&#xff1a;通过配置文件配置、通过命令配置、通过图形化的网络连接菜单配置…

DllMain详解

1 DLL的进入/退出函数 1.1 DllMain简介 跟exe有个main或者WinMain入口函数一样&#xff0c;DLL也有一个入口函数&#xff0c;就是DllMain。以“DllMain”为关键字&#xff0c;来看看MSDN帮助文档怎么介绍这个函数的。 The DllMain function is an optional method of entr…

linux安装tensorflow教程,真正从零开始,TensorFlow详细安装入门图文教程!

在正式开始之前我想说&#xff1a;一定要注意窗口给出的提示(英文)。在实际操作中可能会碰到各种各样的问题&#xff0c;但常见的问题其实都可以根据它的报错信息找到原因&#xff0c;只要上网搜一搜相应的信息就能解决&#xff0c;甚至它自己就会给出解决的建议。如果你发现你…

引路蜂地图API:Gis.Navigation包定义

本包提供了路口到路口实时导航API&#xff0c;从地图服务器返回的路径信息含有文字和路径的地理坐标信息&#xff0c;类NavigationEngine根据路径和当前坐标实现实时导航。它内部含用三个工作线程&#xff1a; Location Monitor 实时监视当前位置坐标是否偏离路径&#xff0c;如…

有些垃圾网站转载都不会

有时会看到我的文章被转载&#xff0c;只要保留作者信息和原文链接&#xff0c;并且忠实于原文都是很欢迎的。这里的忠实原文应该是最基本的了吧&#xff0c;转载嘛&#xff0c;最简单的也就是拷贝粘贴吧&#xff0c;可发现有些垃圾网站&#xff0c;连拷贝粘贴都做不好&#xf…