本文粗略的介绍下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的原理)的更多相关文章

  1. Java中IO流中所涉及到的各类方法介绍

    IO流之字节流 (1)IO用于在设备间进行数据传输的操作 (2)分类: A:流向 输入流 读取数据 输出流 写出数据 B:数据类型 字节流 字节输入流 字节输出流 字符流 字符输入流 字符输出流 注意 ...

  2. 6.11---字节输入流数据根据字节输出流存到文件中---io流概念及分类---文件存储的原理和记事本打开的原理---字节流读取文件的原理---文件复制的原理

  3. 揭开Java IO流中的flush()的神秘面纱

    大家在使用Java IO流中OutputStream.PrintWriter --时,会经常用到它的flush()方法. 与在网络硬件中缓存一样,流还可以在软件中得到缓存,即直接在Java代码中缓存. ...

  4. Java中IO流的总结

    有关Java中IO流总结图 流分类 按方向分 输入流 输出流 按单位分 字节流 字符流 按功能分 节点流 处理流(过滤流) 其他 所有的流继承与这四类流:InputSteam.OutputStream ...

  5. JAVA中IO流总结

    本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/42119261 我想你对JAVA的IO流有所了解,平时使用的 ...

  6. 第54节:Java当中的IO流(中)

    Java当中的IO流(中) 删除目录 // 简书作者:达叔小生 import java.io.File; public class Demo{ public static void main(Stri ...

  7. java 中 IO 流分为几种?(未完成)

    java 中 IO 流分为几种?(未完成)

  8. Java当中的IO流(中)

    Java当中的IO流(中) 删除目录 import java.io.File; public class Demo{ public static void main(String[] args){ / ...

  9. io流中的装饰模式对理解io流的重要性

    为了说明 io流中的装饰者模式对理解io流的重要性,我想先简要介绍以下io的装饰模式. 装饰(decorator)你也可以翻译成修饰.比如:一个会精通化学数学的物理学家.在这个"物理学家&q ...

随机推荐

  1. Newtonsoft.Json反序列化(Deserialize)出错:Bad JSON escape sequence

    使用Newtonsoft.Json反序列化收到的字串为JObject或其它支持的数据模型,有时错误,提示如下: Bad JSON escape sequence: \c. Path , positio ...

  2. [leetcode]45. Jump Game II青蛙跳(跳到终点最小步数)

    Given an array of non-negative integers, you are initially positioned at the first index of the arra ...

  3. Sass入门及知识点整理

    Sass 快速入门 | SASS 中文网 文档链接:https://www.sasscss.com/getting-started/ 前言 之前整理了一篇关于Less的,现在就来整理一下关于Sass的 ...

  4. vue 前端框架 目录

    vue 前端框架 目录   vue-目录 ES6基础语法 vue基础语法 Vue.js的组件化思想 —上 Vue.js的组件化思想 —下 Vue + Vue-Router结合开发 SublimeSer ...

  5. CSS实现左侧多级菜单栏

    首先看要实现的效果, 主要是关心技术实现, 所以没怎么美化 我也是初学html, 所以写的比较啰嗦 1. 使用列表将内容显示出来 <!DOCTYPE html><html>&l ...

  6. c#npoi 报错Cannot get a numeric value from a text cell 的解决

    一般是因为cell里边的值为数字导致,有时变成文本格式还是解决不了这个问题. 下边的代码是c# 改变设置cell类型的方法 是用这个参数 CellType.String Row.GetCell((in ...

  7. [Machine Learning] some concept about the CV

    Cross-validation VS SSE CV is not designed to improve the fit on the training data, but it won't nec ...

  8. Installing TensorFlow on Ubuntu or Windows

    Installing TensorFlow on Ubuntu 显卡驱动:http://developer2.download.nvidia.com/compute/cuda/8.0/secure/P ...

  9. Axure RP Extension for Chrome 插件安装

    描述 我的chmod浏览器上不去谷歌商店,我用的是蓝灯,登上商店后搜索Axure RP Extension for Chrome,下载安装,完成后进入这个插件的详细信息: 使用 打开用axure生成的 ...

  10. # 2019-2020.3 《java程序设计》第一周学习总结

    2019-2020-3 <Java 程序设计>第一周学习总结 在本周的学习中,学习到了好多也收获了好多,从最基础的安装虚拟机开始,根据老师的博客中的教程一步一步的进行,在这过程中也遇到了好 ...