【Stream—6】BufferedStream相关知识分享
一、简单介绍以下BufferedStream
在前几章的讲述中,我们已经能够掌握流的基本特性和特点,一般进行对流的处理时,系统肩负着IO所带来的开销,调用十分频繁,这时候就应该想个办法减少这种开销,而且必须在已有的Stream进行扩展,有了以上2点要求,那么我们今天的主题BufferedStream闪亮登场了。BufferedStream能够实现流的缓存,换句话说也就是在内存中能够缓存一定的数据而不是时时给系统带来负担,同时BufferedStream可以对缓存中的数据进行写入或读取,所以对流的性能带来一定的提升,但是无法同时进行读取或写入工作,如果不使用缓冲区也行,BufferedStream能够保证不用缓冲区时不会降低因缓冲区带来的读取或写入性能的下降
二、如何理解缓冲区
缓冲区是内存中的一块连续区域,用来缓存或临时存储数据,也就是说可以通过缓冲区逐步对数据进行读取或写入操作。BufferedStream中的缓冲区可以由用户设定,其表现形式为Byte数组,想象下没有缓冲区将是多么的可怕,假如我们的非固态硬盘没有缓冲区,如果我们下载速度达到惊人的10m左右,那么下载一个2G或者更大的文件时,磁头的读写是非常的频繁,直接的结果是磁头寿命急剧减少,甚至将硬盘直接烧毁或损坏。
三、BufferedStream的优势
理解了缓冲区的重要性后,让我们再来谈一下BufferedStream的优势,首先大家肯定觉得疑惑,为什么MemoryStream同样也是在内存中对流进行操作,和BufferedStream有什么区别呢?BufferedStream并不是将所有内容都存放到内存中,而MemoryStream则是,BufferedStream必须跟其他流如FileStream结合使用,而MemoryStream则不需要,聪明的你肯定能够想到,BufferedStream必然类似于一个流的包装类,对流进行“缓存功能的扩展包装”,所以BufferedStream的优势不仅体现在其原有的缓存功能上,更体现在如何帮助原有的类实现其功能上的扩展层面上。
四、BufferedStream的构造
1、BufferedStream(Stream stream)
其实BufferedStream的构造主要功能还是设置缓冲区大小,如果没有制定则默认是用4096字节的进行初始化
2、BufferedStream(Stream stream, int i)
第二个参数是手动制定缓冲区大小,第一次使用此构造函数初始化BufferedStream对象时分配共享读/写缓冲区。如果所有的读和写大小都等于缓冲区大小,则不使用共享缓冲区、
五、BufferedStream的属性
1、CanRead已重写。
获取一个值,该值指示当前流是否支持读取。如果支持读取,则为true;如果流已关闭或者时通过只读访问方式打开的,则为false;如果Stream派生的类不支持读取,则对StreamRerader、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。支持搜索到超出流长度的任何位置。
六、BufferedStream的方法
BufferedStream的方法基本上和Stream类一致,没有其独有的方法
七、简单示例:李用socket读取网页并保存在本地
public class Server
{
//端口
private const int webPort = ;
//默认接收缓存大小
private byte[] receiveBufferBytes = new byte[];
//需要获取网页的url
private readonly string _webPageUrl; public Server(string webPageUrl)
{
_webPageUrl = webPageUrl;
} /// <summary>
/// 从网页上获取数据
/// </summary>
public void FetchWebPageData()
{
if (!string.IsNullOrWhiteSpace(_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($"远程服务器名:{iphe.HostName}");
//通过主机信息获取其IP
IPAddress[] address = iphe.AddressList;
IPEndPoint ipep = new IPEndPoint(address[], );
//实例化一个socket用于接收网页数据
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//连接
socket.Connect(ipep);
if (socket.Connected)
{
//发送头文件,这样次啊能下载网页数据
socket.Send(Encoding.ASCII.GetBytes(GetHeader(webPageUrl)));
}
else
{
return;
}
//接收头一批数据
var count = socket.Receive(receiveBufferBytes);
//转化为string
var getString = Encoding.Default.GetString(receiveBufferBytes);
//创建流文件
FileStream fs=new FileStream(@"f:\\test.html",FileMode.OpenOrCreate);
//创建缓存流
BufferedStream bs=new BufferedStream(fs);
using (fs)
{
using (bs)
{
byte[] finalContent = Encoding.Default.GetBytes(getString.ToCharArray());
//将头一批数据写入本地硬盘
bs.Write(finalContent,,finalContent.Length);
//循环通过socket接收数据
while (count > )
{
count = socket.Receive(receiveBufferBytes, receiveBufferBytes.Length, SocketFlags.None);
//直接将接收到的byte数据写入本地硬盘
bs.Write(receiveBufferBytes, , receiveBufferBytes.Length);
Console.WriteLine(Encoding.Default.GetString(receiveBufferBytes));
}
}
}
} /// <summary>
/// 得到Header
/// </summary>
/// <param name="webPageUrl"></param>
/// <returns></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>
public string GetRelativeUrlByStrUrl(string strUrl)
{
var iIndex = strUrl.IndexOf(@"//", StringComparison.Ordinal);
if (iIndex <= )
{
return "/";
} var strTemp = strUrl.Substring(iIndex + );
iIndex = strTemp.IndexOf(@"/", StringComparison.Ordinal);
if (iIndex > )
{
return strTemp.Substring(iIndex);
} return "/";
} /// <summary>
/// 根据Url得到Host
/// </summary>
/// <param name="strUrl">网页Url</param>
/// <returns></returns>
public string GetHostNameByStrUrl(string strUrl)
{
var iIndex = strUrl.IndexOf(@"//", StringComparison.Ordinal);
if (iIndex <= )
{
return "";
} var strTemp = strUrl.Substring(iIndex + );
iIndex = strTemp.IndexOf(@"/", StringComparison.Ordinal);
if (iIndex > )
{
return strTemp.Substring(, iIndex);
} return strTemp;
}
}
好了,BufferedStream相关知识就分享到这里了。
【Stream—6】BufferedStream相关知识分享的更多相关文章
- 【Stream—7】NetworkStream相关知识分享
一.NetworkStream的作用 和先前的流有所不同,NetworkStream的特殊性可以在它的命名空间中得以了解(System.Net.Sockets),聪明的你马上就会反应过来:既然是在网络 ...
- FileStream相关知识分享
一.如何理解FIleStream 通过前3章的学些,相信大家对于Stream已经有一定的了解,但是又如何去理解FileStream呢?请看下图: 我们磁盘中的任何文件都是通过二进制数组组成,最为直观的 ...
- MemoryStream相关知识分享
一.简单介绍一下MemoryStream MemoryStream是内存流,为系统内存提供读写操作,由于MemoryStream是通过无符号字节数组组成的,可以说MemoryStream的性能可以算比 ...
- StreamWriter 相关知识分享
在介绍StreamWriter之前,我们首先来了解一下它的父类TextWriter. 一.TextWriter 1.TextWriter的构造函数和常用属性方法 下面是TextWriter的构造函数: ...
- XML的相关基础知识分享(二)
前面我们讲了一下XML相关的基础知识(一),下面我们在加深一下,看一下XML高级方面. 一.命名空间 1.命名冲突 XML命名空间提供避免元素冲突的方法. 命名冲突:在XML中,元素名称是由开发者定义 ...
- XML的相关基础知识分享
XML和Json是两种最常用的在网络中数据传输的数据序列化格式,随着时代的变迁,XML序列化用于网络传输也逐渐被Json取代,前几天,单位系统集成开发对接接口时,发现大部分都用的WebService技 ...
- 关于StreamReader的知识分享
今天我们来简单的介绍一下StreamReader,在将StreamReader之前,我们先来了解一下他的父类:TextReader.对于TextReader,大家可能比较陌生,下面我们来看一下Text ...
- listener监听器的相关知识
从别人的博客上我学习了listener的相关知识现在分享给大家 1.概念: 监听器就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象发生上 ...
- 【转】java NIO 相关知识
原文地址:http://www.iteye.com/magazines/132-Java-NIO Java NIO(New IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的 ...
随机推荐
- Mybaits 源码解析 (三)----- Mapper接口底层原理(为什么Mapper不用写实现类就能访问到数据库?)
上一篇我们讲解到mapperElement方法用来解析mapper,我们这篇文章具体来看看mapper.xml的解析过程 mappers配置方式 mappers 标签下有许多 mapper 标签,每一 ...
- 从零开始搭建Electron+Vue+Webpack项目框架,一套代码,同时构建客户端、web端(一)
摘要:随着前端技术的飞速发展,越来越多的技术领域开始被前端工程师踏足.从NodeJs问世至今,各种前端工具脚手架.服务端框架层出不穷,“全栈工程师”对于前端开发者来说,再也不只是说说而已.在NodeJ ...
- CMMS系统中工单派案&调度
系统为客户经理提供一个有效的调度控制台,由客户经理负责将需要外派现场处理的工单进行统一的分配调度,系统显示每个技术人员的时间表,根据专业技能.可用性.距离或其他资格标准筛选技术服务人员,并向调度人员提 ...
- The usage of Markdown---引用
目录 1. 序言 2. 引用与嵌套引用 3. 列表中的引用 更新时间:209.09.14 1. 序言 在本篇,我们来仔细谈一下Markdown的引用. 2. 引用与嵌套引用 在Markdown ...
- Mybatis和Mysql的Datetime的一些问题
Mysql的时间类型 时间类型有time, date, datetime, timestamp 如Mysql官方文档所述: time 没有date,date没有time,datetime是date和t ...
- LeetCode刷题笔记(6)按照索引计算int[] 数组中的和([Time Limit Exceeded]问题)
Easy303 Easy633 package easy; public class e303 { private int[] sums; public e303(int[] nums) { sums ...
- (五)Unity插件生成
1)新建空的AndroidStudio工程,但是新建过程时最小SDK版本要与unity一致,如下图所示,本次操作均为api16 2)创建Library,如下图所示,新建module,然后选择Andro ...
- 虚拟机--python环境配置
1.安装VMware 2.安装Ubantu (1)打开VMware,打开编辑-->首选项,更改虚拟机存储的位置. (2)创建新的虚拟机(自定义): (3)编辑虚拟机--点击CD/VCD--更改成 ...
- Python网络爬虫之cookie处理、验证码识别、代理ip、基于线程池的数据爬去
本文概要 session处理cookie proxies参数设置请求代理ip 基于线程池的数据爬取 引入 有些时候,我们在使用爬虫程序去爬取一些用户相关信息的数据(爬取张三“人人网”个人主页数据)时, ...
- 【Redis深度历险】那些年Redis的数据结构
[Redis深度历险]那些年Redis的数据结构 Redis端口号6379的来源 Redis的端口号是6379,但这个端口号并不是随机选择的,源于"MERZ",这个单词在手机当中的 ...