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 ...
随机推荐
- java项目测试或者不使用request,如何获取webroot路径
1.使用jdk中的方法,然后根据项目编译后的文件存在的位置,获取到classes目录,然后向上级查询获取String path = EngineTest.class.getResource(" ...
- 34 【kubernetes】安装手册
全文参考了两篇中文文档: 1,https://www.cnblogs.com/RainingNight/p/using-kubeadm-to-create-a-cluster.html 2,http: ...
- 93. Restore IP Addresses产生所有可能的ip地址
[抄题]: Given a string containing only digits, restore it by returning all possible valid IP address c ...
- CentOS7 使用ifconfig命令 ENS33没有IP地址的解决办法
最近在研究和学习Linux操作系统,我并没有安装独立的Linux操作系统,我选择在虚拟机上安装Linux操作系统.我选择的虚拟机的版本是VMware Workstation Pro14,然后在虚拟机上 ...
- python 数据库操作类
#安装PyMySQL:pip3 install PyMySQL #!/usr/bin/python3 #coding=utf-8 #数据库操作类 from datetime i ...
- 20172325 2018-2019-2 《Java程序设计》第八周学习总结
20172325 2018-2019-2 <Java程序设计>第八周学习总结 教材学习内容总结 一.堆 1.什么是堆? 具有两个附加属性的一个二叉树. 堆分为小顶堆和大顶堆. 最小堆:对每 ...
- 目录命令(tree)
TREE 命令: // 描述: 以图形方式显示驱动器中路径或磁盘的目录结构. // 语法: tree [<Drive>:][<Path>] [/f] [/a] // 参数: / ...
- 【Mybatis】MyBatis配置文件的使用(二)
本例在[Mybatis]MyBatis快速入门(一)基础上继续学习XML映射配置文件 MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置(settings)和属性(properti ...
- for循环的实例
1.大马驮2石粮食,中马驮1石粮食,两头小马驮一石粮食,要用100匹马,驮100石粮食,该如//首先我们要知道一百石粮食需要这些马分别几匹 //第一个是大马,需要五十匹马for(var x=0;x&l ...
- python实现netcat部分功能源代码
#!/opt/local/bin/python2.7 import sys import socket import getopt import threading import subprocess ...