本文粗略的介绍下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. 图像处理项目——生成csv文件提高读取效率

    利用pyhton脚本生成csv文件 *开发环境为windows PyCharm*使用的是pyhton脚本*生成人脸和人脸对应的标签的csv文件 一:主要步骤 1.载入对应路径2.提取每一张图片对应的位 ...

  2. 528. Random Pick with Weight index的随机发生器

    [抄题]: Given an array w of positive integers, where w[i] describes the weight of index i, write a fun ...

  3. loongnix社区

    http://www.loongnix.org/index.php/%E9%A6%96%E9%A1%B5

  4. includes() 方法

    字符串的includes()和数组中的includes()判断有没有括号里面的值,有的话为true,没有为false. 详细解析:https://blog.csdn.net/wu_xianqiang/ ...

  5. linux下apt安装mysql导致mysql.user table is damaged

    笔者在ubuntu下用 apt install mysql-server类似的命令安装mysql, 安装了最新版的mysql5.7,覆盖了操作系统内置的数据库mysql系统库. 最初启动mysql出错 ...

  6. pycharm快捷键及中文说明【使用翻译工具一条一条翻译】

    Search Everywhere: Double Shift Go to File : Ctrl+Shilf+N Recent Files: Ctrl+E Navigation Bar: Alt+H ...

  7. python基础之Day7part1集合

    一.集合 1.定义 s=set() 2.特点 每个元素必须是不可变类型,但集合本身是可变类型的,有add和remove等功能 3.用途 去重(原理:for循环if判断元素是否已存在,不存在则追加) 关 ...

  8. python_day12_html

    目录: 简单web的服务器代码 html简介 html常用标签 一.简单web的服务器代码 1.简单python服务器代码: import socket def main(): sock = sock ...

  9. 【转】nc 使用说明

    netcat是网络工具中的瑞士军刀,它能通过TCP和UDP在网络中读写数据.通过与其他工具结合和重定向,你可以在脚本中以多种方式使用它.使用netcat命令所能完成的事情令人惊讶. netcat所做的 ...

  10. Nodejs之路:异步I/O的过程

    对于Node中的异步I/O调用,从发出调用到回调执行,看起来像普通的js异步,但是流程却和普通js那些消息队列完全不同,整个过程经历了哪些? 下面以Windows平台下为例: 一,异步调用第一阶段: ...