Java中IO流中的装饰设计模式(BufferReader的原理)
本文粗略的介绍下JavaIO的整体框架,重在解释BufferReader/BufferWriter的演变过程和原理(对应的设计模式)
一.JavaIO的简介
流按操作数据分为两种:字节流与字符流.
流按流向分为:输入流(读),输出流(写)。
字符流由来就是:早期的字节流+编码表,为了更便于操作文字数据。
记住:只要是操作字符数据,应该优先使用字符流。
字节流的抽象基类:InputStream ,OutputStream。
字符流的抽象基类:Reader , Writer。
二.JavaIO中的流对象的继承和字节流,字符流的对应关系.
InputStream字节输入流:

OutputStream:字节输出流:

InputStream与OutputStream之间的对应关系:

Reader :字符输入流

Writer :字符输出流
Reader与Writer之间的对应关系
输入字节流、输入字符流之间对应关系
输出字节流、输出字符流之间对应关系
转换流 :InputStreamReader,OutputStreamWriter
转换流的由来:字符流与字节流之间的桥梁 ,方便了字符流与字节流之间的操作
转换流的应用:字节流中的数据都是字符时,转成字符流操作更高效。
标准输入输出流 :
System类中的字段:in,out。它们各代表了系统标准的输入和输出设备,默认输入设备是键盘,输出设备是显示器。
System.in的类型是InputStream.
System.out的类型是PrintStream是OutputStream的子类FilterOutputStream 的子类.
举例引入:从原始IO----->用字符数组作为缓冲区---->用IO中的BufferReader/BufferWriter----->JavaIO中的设计模式(装饰设计模式)
①使用最原始的方式拷贝方式代码:
/*
* 需求:作业:将c盘的一个文本文件复制到d盘。
*
* 思路:
* 1,需要读取源,
* 2,将读到的源数据写入到目的地。
* 3,既然是操作文本数据,使用字符流。
*
*/
public class CopyTextTest {
public static void main(String[] args) throws IOException {
//1,读取一个已有的文本文件,使用字符读取流和文件相关联。
FileReader fr = new FileReader("IO流_2.txt");
//2,创建一个目的,用于存储读到数据。
FileWriter fw = new FileWriter("copytext_1.txt");
//3,频繁的读写操作。
int ch = 0;
while((ch=fr.read())!=-1){
fw.write(ch);
}
//4,关闭流资源。
fw.close();
fr.close();
}
}
②引入字符数组作为缓冲区:(循环次数小,效率高)
public class CopyTextTest_2 {
private static final int BUFFER_SIZE = 1024;
public static void main(String[] args) {
FileReader fr = null;
FileWriter fw = null;
try {
fr = new FileReader("IO流_2.txt");
fw = new FileWriter("copytest_2.txt");
//创建一个临时容器,用于缓存读取到的字符。
char[] buf = new char[BUFFER_SIZE];//这就是缓冲区。
//定义一个变量记录读取到的字符数,(其实就是往数组里装的字符个数)
int len = 0;
while((len=fr.read(buf))!=-1){
fw.write(buf, 0, len);
}
} catch (Exception e) {
// System.out.println("读写失败");
throw new RuntimeException("读写失败");
}finally{
if(fw!=null)
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
if(fr!=null)
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
原理图:

缓冲区的出现提高了文件的读写效率,有缓冲区可以提高效率,在Java中把缓冲区进行了封装,关闭缓冲区就是关闭的被缓冲的流对象!所以只需要关闭缓冲区就可以,不必要再关闭流了。
③引入BufferWriter(缓冲区的出现提高了对数据的读写效率,缓冲区要结合流才可以使用,在流的基础上对流的功能进行了增强)
public class CopyTextByBufTest {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("buf.txt");
BufferedReader bufr = new BufferedReader(fr);
FileWriter fw = new FileWriter("buf_copy.txt");
BufferedWriter bufw = new BufferedWriter(fw);
String line = null;
while((line=bufr.readLine())!=null){
bufw.write(line);
bufw.newLine();
bufw.flush();
}
/*
int ch = 0;
while((ch=bufr.read())!=-1){
bufw.write(ch);
}
*/
bufw.close();
bufr.close();
}
}
字符流缓冲区:
BufferedWriter:newLine();
BufferedReader: readLine();
Buffer***的原理图

④☆☆☆装饰设计模式
装饰设计模式的简易代码:
public class PersonDemo {
public static void main(String[] args){
Person p = new Person();
p.chifan();
NewPerson p1 = new NewPerson(p);
p1.chifan();
NewPerson2 p2 = new NewPerson2();
p2.chifan();
}
}
class Person{
void chifan(){
System.out.println("吃饭");
}
}
//这个类的出现是为了增强Person而出现的。
class NewPerson{
private Person p ;
NewPerson(Person p){
this.p = p;
}
public void chifan(){
System.out.println("开胃酒");
p.chifan();
System.out.println("甜点");
}
}
class NewPerson2 extends Person{
public void chifan(){
System.out.println("开胃酒");
super.chifan();
System.out.println("甜点");
}
}
NewPerson是对Person采用了装饰设计模式对Person对象的功能,NewPerson2是继承了Person,对对象的功能进行增强。
装饰和继承都能实现一样的特点:进行功能的扩展增强,但是他们之前是有区别的,装饰更加灵活。
程序输出:
吃饭
开胃酒
吃饭
甜点
开胃酒
吃饭
甜点
对以上的代码的具体分析贴图:

装饰和继承都能实现一样的特点:对类对象的功能的扩展增强,区别有哪些?
假设首先有一个继承体系如下:(TextWriter,MediaWriter并不存在)
Writer |--TextWriter:用于操作文本 |--MediaWriter:用于操作媒体。
想要对操作的动作进行效率的提高。按照面向对象,可以通过继承对具体的进行功能的扩展,效率提高需要加入缓冲技术,上面的体系结构变成如下:
Writer |--TextWriter:用于操作文本 |--BufferTextWriter:加入了缓冲技术的操作文本的对象。 |--MediaWriter:用于操作媒体。 |--BufferMediaWriter:
到这里就可以了,能达到对功能增强的目标,但是这样做好像并不理想。
如果这个体系进行功能扩展,又多了一些其他的流对象(****Writer,****Reader。。。。)
那么这个流要提高效率,是不是也要产生子类呢?
答案是:是。这时就会发现只为提高功能,进行的继承,导致继承体系越来越臃肿,不够灵活。
重新思考这个问题?
既然加入的都是同一种技术--缓冲。
前一种是让缓冲和具体的对象相结合。
可不可以将缓冲进行单独的封装,哪个对象需要缓冲就将哪个对象和缓冲关联。
通过上面的代码的分析,可以使用装饰设计模式的思想:
class Buffer{
Buffer(TextWriter w)
{
}
Buffer(MediaWirter w)
{
}
}
这样Buffer仅仅对传入的TextWriter和MediaWriter进行操作,下面传入一个Writer,就对Writer中的所有子类进行了操作。
//缓冲对象进行的也是写的操作,所以要继承Writer
class BufferWriter extends Writer{
BufferWriter(Writer w)
{
}
}
这样Writer的体系结构变成如下:
Writer
|--TextWriter:用于操作文本
|--MediaWriter:用于操作媒体。
|--BufferWriter:用于提高效率。
和上面最开始的通过继承增强功能的方式相比:
这两个体系相比,装饰比继承灵活,如果想对已有体系进行功能的扩展,首先要想到的就是装饰模式
装饰模式的特点:装饰类和被装饰类都必须所属同一个接口或者父类。


字节流和字符流的区别:
字节流能处理的数据单元不一样,数据的格式不一样,MP3,文本等。字符流只能操作文字。
字符流用的是缓冲区是字符数组。字节流用的缓冲区是字节数组。
字节流一次就不能读取出一个中文文字。字符流可以。
能用字符流进行媒体文件的操作吗?
字符流的特点在于,读取完字节之后并没有直接去往目的地里面去写而是去查表(查表有对应的数据,然后我们接着写不一样吗,是的,真的是这样的,但就是这个地方出了问题),万一读到的这个字节数据在表里查不到内容呢?文字有特定的编码格式,而这些媒体文件没有,他们都有其自身的编码方式,而且这些编码方式都是千变万化的,他拿到码表去查没有找到对应的,怎么办?码表会拿一些未知字符区的数据来表示这个没有对应的情况,就直接写到目的数据里面去了,这样元数据和目的数据就不一致了,这样就不能被图片编辑器所解析,解析不了。
不要尝试用字符流去操作媒体文件,你操作完之后有可能发现操作之后的数据大小和源数据的数据大小不一致。
Java中IO流中的装饰设计模式(BufferReader的原理)的更多相关文章
- Java中IO流中所涉及到的各类方法介绍
IO流之字节流 (1)IO用于在设备间进行数据传输的操作 (2)分类: A:流向 输入流 读取数据 输出流 写出数据 B:数据类型 字节流 字节输入流 字节输出流 字符流 字符输入流 字符输出流 注意 ...
- 6.11---字节输入流数据根据字节输出流存到文件中---io流概念及分类---文件存储的原理和记事本打开的原理---字节流读取文件的原理---文件复制的原理
- 揭开Java IO流中的flush()的神秘面纱
大家在使用Java IO流中OutputStream.PrintWriter --时,会经常用到它的flush()方法. 与在网络硬件中缓存一样,流还可以在软件中得到缓存,即直接在Java代码中缓存. ...
- Java中IO流的总结
有关Java中IO流总结图 流分类 按方向分 输入流 输出流 按单位分 字节流 字符流 按功能分 节点流 处理流(过滤流) 其他 所有的流继承与这四类流:InputSteam.OutputStream ...
- JAVA中IO流总结
本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/42119261 我想你对JAVA的IO流有所了解,平时使用的 ...
- 第54节:Java当中的IO流(中)
Java当中的IO流(中) 删除目录 // 简书作者:达叔小生 import java.io.File; public class Demo{ public static void main(Stri ...
- java 中 IO 流分为几种?(未完成)
java 中 IO 流分为几种?(未完成)
- Java当中的IO流(中)
Java当中的IO流(中) 删除目录 import java.io.File; public class Demo{ public static void main(String[] args){ / ...
- io流中的装饰模式对理解io流的重要性
为了说明 io流中的装饰者模式对理解io流的重要性,我想先简要介绍以下io的装饰模式. 装饰(decorator)你也可以翻译成修饰.比如:一个会精通化学数学的物理学家.在这个"物理学家&q ...
随机推荐
- http://ctf.bugku.com/challenges#%E9%80%86%E5%90%91%E5%85%A5%E9%97%A8:bugku--逆向入门
文件是: 分析挺简单,主要是data urls知识点. 首先使用peid检测是否加壳,发现它居然是jpg文件.使用notepad++查看,结果如下. 嗯,百度一下子,知道了data ...
- Swift MD5加密
很多时候我们会用到md5加密,下面是swift 3.0的实现方法: 首先新建桥接文件 xx-Bridging-Header,方法很多,这里就不介绍了. 然后在桥接文件中引入加密库 #import &l ...
- Centos7+hadoop2.7.3+jdk1.8
修改主机名 1. 修改主机名 vi /etc/sysconfig/network ,改为 master , slave1 , slave2 2. source /etc/sy ...
- 震惊!90%的程序员不知道的Java知识!
震惊!90%的程序员不知道的Java知识! 初学Java的时候都会接触的代码 public static void main(String[] args){ ... } 当时就像背公式一样把这行代码给 ...
- Robot Framework浏览器驱动下载
运行robot framework 有时打不开浏览器,可能用到的驱动不对,以下是各浏览器驱动下载,仅供参考!~ 各浏览器下载地址: Firefox浏览器驱动:geckodriver https: ...
- web工程was部署
web.xml调整: 新增如下servlet <servlet> <servlet-name>SimpleFileServlet</servlet-name> &l ...
- Knockout.js快速学习笔记
原创纯手写快速学习笔记(对官方文档的二手理解),更推荐有时间的话读官方文档 框架简介(Knockout版本:3.4.1 ) Knockout(以下简称KO)是一个MVVM(Model-View-Vie ...
- A - ACboy needs your help again!
ACboy was kidnapped!! he miss his mother very much and is very scare now.You can't image how dark th ...
- Forward团队-爬虫豆瓣top250项目-项目进度
项目地址:https://github.com/xyhcq/top250 我们的项目是爬取豆瓣top250的电影的信息,在做这个项目前,我们都没有经验,完全是从零开始,过程中也遇到了很多困难,不过我们 ...
- Coding能力提升小技巧
一.使用变量的一般原则 1.变量初始化原则: 通常在变量声明时初始化; 在靠近变量第一次使用的位置初始化; 在类的构造函数里初始化变量. 2.作用域: 使变量引用局部化,即把引用到变量的地方尽可能集中 ...



