day19(中)_IO流3(模拟缓冲区,装饰设计模式)


 

1.MyBufferedReader和MyBufferedInputStream

1.模拟字符读取流的缓冲区:

/*根据readLine原理:自定义一个类包含一个功能和readLine一致的方法来模拟以下BufferedReader方法
*/
package myreadline;
import java.io.FileReader;
import java.io.IOException;class MyBufferedReader{private FileReader r;//需要用到FileReader的read方法,因此初始化时传入FileReader对象private char[] chArr=new char[1024];private int pointer=0;MyBufferedReader(FileReader r){this.r=r;}//自定义readLine方法public String readLine()throws IOException{//自定义功能不在内部处理,而是抛出去,让调用者处理
StringBuilder sb=new StringBuilder();//定义一个临时容器模拟缓冲区int ch=0;while((ch=r.read())!=-1){if(ch=='\r') continue;//读下一个进行判断elseif(ch=='\n')return sb.toString();elsesb.append((char)ch);}   /*
    ①以上代码也不可写成
      if(ch==’\r’||ch==’\n’)
       returnsb.toString()
      因为当读到'\r’ 立即返回改行数据,
      但是下次会读'\n’ 会再次返回,此时StringBuilder无数据
 
    ②如果当前平台的换行为'\r’以上方法并不适用
      以上方法仅适用与\r\n或\n换行
      此时直接
      if(ch==’\r’)
         return sb.toString();
      else
        return sb.append((char)ch);
对于以上代码可能发生一种情况:当读到文件最后一行:例如:abcd后面没有回车,此时执行不到sb.toString(),也就是说:虽然存入容器但是这一行不能返回.
     那么加上一个判断(如下): 
*/if(sb.length()!=0)return sb.toString();
return null;//此时读到文件末尾

}//模拟自定义缓冲区,把关闭单独封装在一个方法中public void myClose()throws IOException{r.close();}public static void main(String[] args){MyBufferedReader mbr=null;try{mbr=new MyBufferedReader(new FileReader("4_MyBufferedReader.java"));String line=null;while((line=mbr.readLine_2())!=null)System.out.println(line);}catch(IOException e){throw new RuntimeException("读异常");}finally{try{if(mbr!=null)mbr.myClose();}catch(IOException e){throw new RuntimeException("关闭异常");}}}
}

 

/*
如果不利用StringBuilder而利用
字符数组
*/
public  String readLine_2()throws IOException{pointer=0;int ch=0;while((ch=r.read())!=-1){if(ch=='\r')continue;elseif(ch=='\n')return new String(chArr,0,pointer);elsechArr[pointer++]=(char)ch; }if(pointer!=0)return new String(chArr,0,pointer);return null;
}

模拟readLine方法

2.模拟字节读取流缓冲区:

/*
自定义缓冲区:算法思想:参照示意图
*/  package mybuffered;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io. BufferedOutputStream;
class MyBufferedInputStream{private byte[] buff=new byte[1024];private InputStream is=null;private int pointer=0;//指针用于取出缓冲区(数组)中的元素private int count=0;//计数器用于记录每次从文件中取出的字节数
  MyBufferedInputStream(InputStream is){this.is=is;}public int myBufferedRead()throws IOException{if(count==0){//只有当缓冲区中的数据被读完时,再从文件中//取一部分数据count=is.read(buff);pointer=0;//当count==0,把指针重新移到0角标
     }if(count!=-1){//是否到达文件尾--count;//读取一个字节,count-1return (int)buff[pointer++] & 255;//0x00ff
     }elsereturn -1;}public void close()throws IOException{is.close();}
}class TestBuffered{public static void main(String[] args)throws IOException{
  //用自定义缓冲区拷贝MP3
 MyBufferedInputStream mbis=new MyBufferedInputStream(new FileInputStream("e:\\song\\Amy Diamond - Heartbeats.mp3"));BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("c:\\Hertbeats.mp3"));long start=System.currentTimeMillis();int aByte=0;System.out.println(aByte=(mbis.myBufferedRead()));
while((aByte=(mbis.myBufferedRead()))!=-1){//从自定义缓冲区中读一个字节,写入到系统的缓冲区
   bos.write(aByte);bos.flush();}long end=System.currentTimeMillis();System.out.println(end-start+"ms");//时间的长短和cpu性能以及其它因素有关
  bos.close();mbis.close();} 
}
模拟字节流缓冲区

2.装饰设计模式:

①概述:

/*
装饰设计模式:(目前学的第三种设计模式)
    当想要对已有的对象进行功能增强时可以定义类,将已有对象(new FileReader)传入,基于已有的功能(read),并提供加强功能(myReadLine).那么自定义的该类成为装饰类.装饰类通常会通过构造方法接收被装饰的对象
并基于被装饰的对象的功能,提供更强的功能*/
//例如:增强人的吃饭功能
class Person{public void eat(){System.out.println("吃饭");}
} 
class SuperPerson{private Person p;SuperPerson(Person p){this.p=p;}public void superEat(){System.out.println("喝小酒");p.eat();System.out.println("甜点");System.out.println("整一根");}
}
class PersonDemo{public static void main(String[] args){Person p=new Person();    p.eat();new SuperPerson(p).superEat();}
}
/*到目前为止已经学到3中设计模式:1.单例设计模式2.模板方法设计模式3.装饰设计模式
*/

②※装饰相对继承优点:

/*在人吃饭例子中,可以不用装饰类,我直接让SuperPerson extends Person,然后复写eat方法不也OK?在举例说明为什么要有装饰设计模式?//MyTextReader类用来操作文件读取,为了提高读操作效率,使用缓冲区技术//又定义一个类MyBufferedTextReader继承它,提供更高效的readLine方法MyReader  <--MyTextReader<--MyBufferedTextReader<--MyMediaReader<--MyBufferedMediaReader//读取多媒体文件,然后为了提高读效率,使用缓冲区<--MyDataReader<--MyBufferedDataReader//同理......  那么,我后期在来个类用于操作读取其它文件,为了高效还得定义缓冲区子类,产生一些缺点:1.使整个体系变得异常冗杂2.后期的扩展性极差那么干脆:找到其参数的共同类型.通过多态形式.可以提高扩展性MyBufferedReader extends MyReader{private MyReader mr;pubic MyBufferedReader(MyReader mr){//MyReader的子类对象均能传入this.mr=mr;                           //谁需要使用缓冲技术,把它传进来}}简化了原有体系结构:MyReader<--MyTextReader<--MyMediaReader<--MyDataReader   <--MyBufferedReader*//*
装饰设计模式对比继承:1.装饰设计模式比继承更加灵活提高扩展性,避免了继承的冗杂而且降低了类与类之间关系2.装饰类因为增强已有对象,具备的功能和已有的功能是相同的只不过提供了更强的功能(这个功能是原有的增强,而不是从本质上改变原有功能:在Reader体系中,例如:装饰类BufferedReader,其中readLine就是增强了FileReader中read功能)那么装饰类和被装饰类通常是同属于一个体系(具有共同的父类/父接口)  
*/

 

鉴于以上我们可以把自定义缓冲区的代码优化下: (改进自定义字符读取流缓冲区)

//把MyBufferedReader修改为装饰类:
package myreadline;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class MyBufferedReader2 extends Reader{//继承Reader,那么必须复写Reader中抽象方法,不然无法创建对象
 private Reader r;
public MyBufferedReader2(Reader r){//多态提高扩展性this.r=r;  
  }public String readLine()throws IOException{StringBuilder sb=new StringBuilder();int ch=0;while((ch=r.read())!=-1){if(ch=='\r') continue;//读下一个进行判断elseif(ch=='\n')return sb.toString();elsesb.append((char)ch);}   if(sb.length()!=0)return sb.toString();
return null;
}//复写close方法public void close()throws IOException{r.close();}//复写abstract int read(char[] cbuf, int off, int len)public int read(char[] cbuf, int off, int len)throws IOException{return 
r
.read(cbuf,off,len);//利用了 传入对象已复写该方法
  }public static void main(String[] args){MyBufferedReader mbr=null;try{mbr=new MyBufferedReader(new FileReader("4_MyBufferedReader.java"));String line=null;while((line=mbr.readLine())!=null)System.out.println(line);}catch(IOException e){throw new RuntimeException("读异常");}finally{try{if(mbr!=null)mbr.close();}catch(IOException e){throw new RuntimeException("关闭异常");}}}
}

3.BufferedReader子类LineNumberReader(相对于BufferedReader提供更强功能)

①.LineNumberReader示例:

/*
在BufferedReader下有一个子类:LineNumberReader跟踪行号的缓冲字符输入流,进一步加强功能.打印每行的同时可以带上行号
*/
package bufferedreader;
import java.io.LineNumberReader;
import java.io.FileReader;
import java.io.IOException;
class LineNumberReaderDemo{public static void main(String[] args){LineNumberReader lnr=null;try{lnr=new LineNumberReader(new FileReader("7_LineNumberReader.java"));String line=null;lnr.setLineNumber(10);//那么行号将从11开始while((line=lnr.readLine())!=null)System.out.println(lnr.getLineNumber()+":"+line);}catch(IOException e){e.printStackTrace();}finally{try{if(lnr!=null)lnr.close();}catch(IOException e){e.printStackTrace();}}}
}

LineNumberReader

②自定义MyLineNumberReader方法:

 
package mylinenumber;import java.io.Reader;
import java.io.FileReader;
import java.io.IOException;
import myreadline.MyBufferedReader2;class MyLineNumberReader extends MyBufferedReader2{//在MyBufferedReader2已有方法,不再重复定义private int lineNumber=0;//行号public MyLineNumberReader(Reader r){super(r);}//设置行号public void mySetLineNumber(int lineNumber){this.lineNumber=lineNumber;}//获取行号public int myGetLineNumber(){return lineNumber; }public String myReadLine()throws IOException{++lineNumber;//读一行自增一次return super.readLine();//提高代码重用性
    }}class MyLineNumberDemo{public static void main(String[] args){MyLineNumberReader mlnr=null;try{mlnr=new MyLineNumberReader(new FileReader("8_MyLineNumberReader.java"));String line=null;mlnr.mySetLineNumber(100);while((line=mlnr.myReadLine())!=null)System.out.println(mlnr.myGetLineNumber()+":"+line);}catch(IOException e){e.printStackTrace();}finally{try{if(mlnr!=null)mlnr.close();}catch(IOException e){e.printStackTrace();}}}
}
MyLineNumberReader

转载于:https://www.cnblogs.com/yiqiu2324/archive/2013/05/18/3085750.html

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

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

相关文章

手把手教你学Dapr - 8. 绑定

介绍使用绑定&#xff0c;您可以使用来自外部系统的事件触发您的应用程序&#xff0c;或与外部系统交互。这个构建块为您和您的代码提供了几个好处&#xff1a;消除连接和轮询消息系统&#xff08;如队列和消息总线&#xff09;的复杂性关注业务逻辑&#xff0c;而不是如何与系…

Android之百度地图定位最详细使用总结

Android之百度定位 如果项目里面有定位功能的话,一般还是觉得蛮高大上的,我们项目用的百度定位,到网上找了很多资料,很多都不全面,很多博客都没有小伙伴期望得到当前的省和城市出来,然后自己动手也有很多错误,不知道错在哪里,也在网上找为什么…

CountDownLatch应用实战

2019独角兽企业重金招聘Python工程师标准>>> 1. CountDownLatch简介 一个同步辅助类&#xff0c;在完成一组正在其他线程中执行的操作之前&#xff0c;它允许一个或多个线程一直等待。其本质就是一个共享锁。 他最主要的作用是用来同步java的线程。 主要有以下三个方…

40张令人震惊的对比图,第一张细思恐极

全世界只有3.14 % 的人关注了爆炸吧知识世界之大&#xff0c;无奇不有。来看Reddit网友们分享的一组对比图&#xff0c;涨涨姿势&#xff01;医生对戴口罩和不戴口罩的培养皿分别&#xff1a;打喷嚏&#xff0c;唱歌&#xff0c;说话和咳嗽之后的区别&#xff08;难怪有些国家疫…

Smark.Data 1.5更新详解

由于一直忙于Beetle的开发和优化&#xff0c;Smark.Data组件已经有很长一段时间更新。这段时间发现Smark.Data在某些情况下不足&#xff0c;而这些情况又比较普遍所以进行了1.5版的更新。其更新的主要功能包括:查询可填充到自定义对象中&#xff0c;可直接执行存储过程和执行存…

C# 数据适配器之 DataAdapter 对象

01 DataAdapter 对象概述DataAdapter 对象是一个数据适配器对象&#xff0c;是DataSet 与数据源之间的桥梁。DataAdapter 对像提供了 4 个属性&#xff0c;用于实现与数据源之间的互通。SelectCommand 属性&#xff1a;向数据库发送查询 SQL 语句。 DeleteCommand 属性&#x…

express 4 简单实现自动注册路由功能

为什么80%的码农都做不了架构师&#xff1f;>>> ##实现 在express&#xff0c;模块的lib/router/index.js 的 proto.route 方法定义附件添加代码&#xff0c;实现自动注册路由方法&#xff1a; var fs require("fs"); var Path require("path&quo…

速战速决?你不会是不行吧......

1 真服了&#xff01;&#xff01;▼2 同猫不同命......▼3 无锡&#xff1a;&#xff1f;&#xff1f;▼4 还是黄金好&#xff1f;▼5 你会不会是不行&#xff1f;&#xff1f;▼6 爸爸&#xff1a;那也太惊喜了...▼7 倒是毫无违和感&#xff1f;▼8 皇上您说的对&…

mysql普通标转分区表_MySQL分区表到普通表互转

由于最近总有人抱怨&#xff0c;数据迁移后执行SQL变慢&#xff0c;经过查看原来是分区导致的问题。原分区根据按月设置RANGE分区&#xff0c;看到这图的时候也许有人就会发现问题.......业务查询SQL&#xff1a;从SQL上看 执行计划确实是走了分区&#xff0c;但为什么没有命中…

C# 用IrisSkin4.dll美化你的WinForm

1. 将IrisSkin4.dll动态文件导入当前项目引用中。具体操作为&#xff1a;解决方案资源管理器->当前项目->引用->右键->添加引用&#xff0c;找到IrisSkin4.dll文件&#xff0c;然后加入即可。建议&#xff0c;最好把IrisSkin4.dll文件放在当前项目\bin\Debug文件中…

全球最大油田、金矿、煤矿、铁矿、铜矿,究竟哪个最值钱?

全世界只有3.14 % 的人关注了爆炸吧知识1世界上最大油田&#xff1a;沙特加瓦尔油田&#xff08;Ghawar Oil field&#xff09;加瓦尔油田位于沙特阿拉伯东部&#xff0c;首都利雅得以东约500km处&#xff0c;它探明的石油可采储量为114.8亿吨&#xff0c;天然气储量9240亿立方…

MVC3快速搭建Web应用(二)

easyui与mvc的结合 上一篇文章发布后&#xff0c;自己又仔细读了数遍&#xff0c;感觉一是文笔太差&#xff0c;二是描述逻辑比较混乱&#xff0c;客观原因是涉及到东西其实蛮多的&#xff0c;那三个步骤不可能在一篇短短的文章中就可以描述清楚。此篇笔者将尽量更加详尽一些。…

这个发热鞋垫厉害了,有它冬天再也不怕脚冷

▲ 点击查看冬天一到&#xff0c;小爆发现身边的“抖友”又开始上线了&#xff01;至于为什么会抖脚&#xff1f;有盆友说&#xff0c;当然不是真的想抖&#xff0c;而是因为脚太冷冷冷了&#xff01;有时候穿了棉袜厚鞋&#xff0c;脚都是冷冰冰的&#xff0c;感觉就像踩在冰窟…

.NET 6新特性试用 | 热重载

前言在以前的开发模式下&#xff0c;我们修改代码后必须重新编译、重新运行才能看到效果。而热重载提供了这样一种特性&#xff0c;它允许你在项目正在运行时修改代码&#xff0c;并将代码更改立即应用于正在运行的应用程序上。热重载的目的是尽可能节省编辑之间的应用重启次数…

加速你的Hibernate引擎(上)

为什么80%的码农都做不了架构师&#xff1f;>>> 1.引言 Hibernate是最流行的对象关系映射&#xff08;ORM&#xff09;引擎之一&#xff0c;它提供了数据持久化和查询服务。 在你的项目中引入Hibernate并让它跑起来是很容易的。但是&#xff0c;要让它跑得好却是需…

Spring MVC 中 HandlerInterceptorAdapter过滤器的使用

一般情况下&#xff0c;对来自浏览器的请求的拦截&#xff0c;是利用Filter实现的&#xff0c;这种方式可以实现Bean预处理、后处理。 Spring MVC的拦截器不仅可实现Filter的所有功能&#xff0c;还可以更精确的控制拦截精度。 Spring为我们提供了org.springframework.web.s…

7部必看的纪录片,每一部都堪称经典,让人叹为观止!

全世界只有3.14 % 的人关注了爆炸吧知识纪录片的一大重要意义&#xff0c;就在于它能将我们的视野和脚步&#xff0c;引向我们无法企及的地方和领域&#xff0c;又能让那些我们曾经到过的地方、经历过的人事&#xff0c;变得更有深意。今天&#xff0c;就给大家分享7部顶级纪录…

通过SQL Server操作MySQL的步骤和方法

在多种数据库环境下&#xff0c;经常会遇见在不同数据库之间转换数据和互相进行操作的情况。以下简要介绍下用SQL Server操作MySQL的步骤和方法。 1 操作前的准备 1.1 安装MySQL驱动 想要在SQL Server中操作MySQL&#xff0c;首先要在SQL Server所在的服务器上安装MySQL的驱动。…

ubuntu 新增mysql用户_Ubuntu中给mysql添加新用户并分配权限

一.Ubuntu下启动mysql方法&#xff1a;/etc/init.d/sudo mysqld二.用户添加bingt;mysql -u rootmysqlgt; grant 权限1,权限2,...权限n on一.Ubuntu下启动mysql方法&#xff1a;/etc/init.d/sudo mysqld二.用户添加bin>mysql -u rootmysql> grant 权限1,权限2,...权限n on…

ABP Framework 5.0 RC.1 新特性和变更说明

.Net 6.0 发布之后&#xff0c;ABP Framework 也在第一时间进行了升级&#xff0c;并在一个多星期后&#xff08;2021-11-16&#xff09;发布了 5.0 RC.1 &#xff0c;新功能和重要变更基本已经确定。5.0版本新特性5.0版本新特性列表&#xff1a;•静态 C# 和 JavaScript 客户端…