黑马程序员【结合源码介绍IO体系框架】
2014-07-13 00:28
399 查看
------- android培训、java培训、期待与您交流! ----------
of Stream)出来,流向个目的地(Sink of Stream)。根据流的方向,可以分成输入流和输出流,一个程序从输入流读取数据向输出流写数据。根据数据类型输入流有可分为字节输入流和字符输入流,输出流分为字节输出流和字符输出流,如下图。
IO体系中四大基本类(抽象类):InputStream,OutputStream,Reader,Writer。InputStream和OutputStream处理8为字节的输入和输出,Reader和Writer处理16位字符(char型)的输入和输出。
InputStream和OutputStream是两个抽象类,从源码中可以看出,类中只是简单的定义了基本的读写方法和关闭流方法。最重要的两个读写方法read()和Writer方法分别是类中唯一的抽象方法,是其子类必须实现的方法。其中FileInputStream中的read()方法和FileOutputStream中的Writer()方法是native本地方法,真正从磁盘读取数据和往磁盘写数据的正是这两个native方法。无论是字符流还是字节流,无论中间经历的多么复杂的过程,数据源如果是磁盘,最终调用的是native
read(),数据目的地是磁盘最终调用native Write()方法。因为Java 是运行在JVM之上的,不能直接与底层硬件和OS交互,只能通过C/C++等语言编写的native方法实现交互。native方法就像是JVM和磁盘之间一个接口,要想对磁盘进行IO操作,程序必须链接到此接口。
ByteArrayStream(ByteArrayInputStream和ByteArrayOutputStream简写)的数据源和数据宿都是内存,其中就没有native方法,所以调用close()方法是没作用的。此类继承自InputStream和OutputStream,但只是简单重写父类的所有方法,用流的思想去操作数组。但是作为字节流的子类,是可以链接在其他字节流上的,比如BufferedInputStream。因为此类操作内存数据的,ByteArrayInputStream部分源码如下:
可以把ByteArrayStream简单的理解成操作字节数组的工具类。
IO架构整体设计利用了decorator模式,以FilterInputStream为例,部分源码如下:
FilterInputStream继承自InputStream,然后又引用的InputStream,这是典型的decorator模式。从源码中可以看出,此类简单重现父类所有方法,调用的都是父类方法。而真正负责装饰InputStream的是FilterInputStream的子类BufferedInputStream、DataInputStream、LineNumberInputStream等。装饰者类必须接受另外一个流对象(被装饰者)作为源。源经过装饰者后会具备一些额外的增强功能。
BufferedInputStream:为输入流提供一个内存缓冲区,解决了每次要用数据的时候都要进行物理读取的问题。
DataInputStream:和DataOutputStream配合使用,实现了直接对java基本数据类型IO操作。
LineNumberInputStream(已弃用):跟踪输入流的行号;有getLineNumber(
)和setLineNumber(int)方法。
看一下DataStream怎么进行装饰的:
最后还有一个略显特殊的类RandomAccessFile,该类是Object的直接子类。从结构图上看,该类不属于IO体系,可能是因为这个类能同时进行文件的读写吧,既属于Input也属于Output不好划分啊。结果自己就傲娇的独立出来了。我们先来看一下这个类和InputStream、OutputStream有什么区别,还是看源码,源码能直接说明问题:
理解了字节流框架,字符流也就非常简单了,无非就是把字节转换成了字符进行操作。先来看一下Reader的部分源码:
Reader和Writer真的可以直接以字符为单位对磁盘进行读写吗?当然不可以,所有的文件在计算机中都是1001的二进制,哪有什么字符。构造InputStreamReader时要传入InputStream,说明读取文件的还是InputStream中的native read(),InputStreamReader的作用是把字节解码成字符,就是所谓的字节流通向字符流的桥梁。
字符流整体框架结构和字节流框架差不多,有一点值得注意:为什么BufferedReader不是FilterReader的子类,怎么直接继承了Reader?很简单,Reader这个类本身就是装饰类(这句话对么??)。
我用了一个星期才把IO框架理解到了这个程度,智商捉急,如有不对的地方,还望有大神能指正。
最后说明一下,这个框架图我是参考的别人的,稍作完善,尊重版权。参考博客
------- android培训、java培训、期待与您交流!
----------详情请查看:http://edu.csdn.net/heima
一、IO框架的概括
初学Java的IO框架,感觉这个体系很庞大,总是理不清头绪。随着学习的不断深入,加之阅读一些IO源代码,对IO框架的整体有了新的认识。首先,理解两个概念输入流和输出流。所谓流,就是数据的有序排列,而流是可以是从某个源(Sourceof Stream)出来,流向个目的地(Sink of Stream)。根据流的方向,可以分成输入流和输出流,一个程序从输入流读取数据向输出流写数据。根据数据类型输入流有可分为字节输入流和字符输入流,输出流分为字节输出流和字符输出流,如下图。
IO体系中四大基本类(抽象类):InputStream,OutputStream,Reader,Writer。InputStream和OutputStream处理8为字节的输入和输出,Reader和Writer处理16位字符(char型)的输入和输出。
二、IO框架的详细说明
1、字节流体系结构
InputStream和OutputStream是两个抽象类,从源码中可以看出,类中只是简单的定义了基本的读写方法和关闭流方法。最重要的两个读写方法read()和Writer方法分别是类中唯一的抽象方法,是其子类必须实现的方法。其中FileInputStream中的read()方法和FileOutputStream中的Writer()方法是native本地方法,真正从磁盘读取数据和往磁盘写数据的正是这两个native方法。无论是字符流还是字节流,无论中间经历的多么复杂的过程,数据源如果是磁盘,最终调用的是native
read(),数据目的地是磁盘最终调用native Write()方法。因为Java 是运行在JVM之上的,不能直接与底层硬件和OS交互,只能通过C/C++等语言编写的native方法实现交互。native方法就像是JVM和磁盘之间一个接口,要想对磁盘进行IO操作,程序必须链接到此接口。
ByteArrayStream(ByteArrayInputStream和ByteArrayOutputStream简写)的数据源和数据宿都是内存,其中就没有native方法,所以调用close()方法是没作用的。此类继承自InputStream和OutputStream,但只是简单重写父类的所有方法,用流的思想去操作数组。但是作为字节流的子类,是可以链接在其他字节流上的,比如BufferedInputStream。因为此类操作内存数据的,ByteArrayInputStream部分源码如下:
public class ByteArrayInputStream extends InputStream { //数据源是数组 public ByteArrayInputStream(byte buf[]) { this.buf = buf; this.pos = 0; this.count = buf.length; } //利用数组指针 逐一读取数组数据 public synchronized int read() { return (pos < count) ? (buf[pos++] & 0xff) : -1; } //没有任何语句 空函数 public void close() throws IOException { } }
可以把ByteArrayStream简单的理解成操作字节数组的工具类。
IO架构整体设计利用了decorator模式,以FilterInputStream为例,部分源码如下:
public class FilterInputStream extends InputStream { //The input stream to be filtered. protected volatile InputStream in; protected FilterInputStream(InputStream in) { this.in = in; } // //调用父类的方法 public int read() throws IOException { return in.read(); } public int read(byte b[]) throws IOException { return read(b, 0, b.length); } public int read(byte b[], int off, int len) throws IOException { return in.read(b, off, len); } public long skip(long n) throws IOException { return in.skip(n); }
FilterInputStream继承自InputStream,然后又引用的InputStream,这是典型的decorator模式。从源码中可以看出,此类简单重现父类所有方法,调用的都是父类方法。而真正负责装饰InputStream的是FilterInputStream的子类BufferedInputStream、DataInputStream、LineNumberInputStream等。装饰者类必须接受另外一个流对象(被装饰者)作为源。源经过装饰者后会具备一些额外的增强功能。
BufferedInputStream:为输入流提供一个内存缓冲区,解决了每次要用数据的时候都要进行物理读取的问题。
DataInputStream:和DataOutputStream配合使用,实现了直接对java基本数据类型IO操作。
LineNumberInputStream(已弃用):跟踪输入流的行号;有getLineNumber(
)和setLineNumber(int)方法。
看一下DataStream怎么进行装饰的:
//DataOutputStream //把Boolean型转换成数字1、0保存到文件 public final void writeBoolean(boolean v) throws IOException { out.write(v ? 1 : 0); incCount(1); } <span style="white-space:pre"> </span>//DataInputStream //读取时,再转换回来 1返回true,0返回false public final boolean readBoolean() throws IOException { int ch = in.read(); if (ch < 0) throw new EOFException(); return (ch != 0); }很简单,就是把Boolean的true/false和1/0相互转换。
最后还有一个略显特殊的类RandomAccessFile,该类是Object的直接子类。从结构图上看,该类不属于IO体系,可能是因为这个类能同时进行文件的读写吧,既属于Input也属于Output不好划分啊。结果自己就傲娇的独立出来了。我们先来看一下这个类和InputStream、OutputStream有什么区别,还是看源码,源码能直接说明问题:
/** * Although RandomAccessFile is not a subclass of * InputStream, this method behaves in exactly the same * way as the {@link InputStream#read()} method of InputStream. */ public int read() throws IOException { Object traceContext = IoTrace.fileReadBegin(path); int b = 0; try { b = read0(); } finally { IoTrace.fileReadEnd(traceContext, b == -1 ? 0 : 1); } return b; } //native方法 读 private native int read0() throws IOException; //native方法 写 private native void write0(int b) throws IOException;虽然RandomAccessFile不是InputStream的子类,但是read()方法和InputStream要完成的功能是一样的,而且read()和write都是native方法。该类和IO体系中的类的最大区别就是可以读也可以写,而且有一个非常强大的seek()方法,能对文件的任意位置进行读写,也就是所谓的随机访问文件。既然不属于IO体系当然也不能使用装饰类,所以只能自己实现,实现了DataInput和DataOutput接口,具备了对基本数据类型进行读写的功能。
2、字节流体系结构
理解了字节流框架,字符流也就非常简单了,无非就是把字节转换成了字符进行操作。先来看一下Reader的部分源码:
public abstract class Reader implements Readable, Closeable { public int read() throws IOException { char cb[] = new char[1]; if (read(cb, 0, 1) == -1) return -1; else return cb[0]; } public int read(char cbuf[]) throws IOException { return read(cbuf, 0, cbuf.length); } //最重要的方法,确实抽象方法 abstract public int read(char cbuf[], int off, int len) throws IOException;
Reader和Writer真的可以直接以字符为单位对磁盘进行读写吗?当然不可以,所有的文件在计算机中都是1001的二进制,哪有什么字符。构造InputStreamReader时要传入InputStream,说明读取文件的还是InputStream中的native read(),InputStreamReader的作用是把字节解码成字符,就是所谓的字节流通向字符流的桥梁。
import sun.nio.cs.StreamDecoder; /** * An InputStreamReader is a bridge from byte streams to character streams: It * reads bytes and decodes them into characters using a specified charset. */ public class InputStreamReader extends Reader { //负责把字节转换成字符 private final StreamDecoder sd; //InputStream读取数据 public InputStreamReader(InputStream in) { super(in); try { sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object } catch (UnsupportedEncodingException e) { // The default encoding should always be available throw new Error(e); } } public int read() throws IOException { return sd.read(); } public int read(char cbuf[], int offset, int length) throws IOException { return sd.read(cbuf, offset, length); } public boolean ready() throws IOException { return sd.ready(); } public void close() throws IOException { sd.close(); } }这是InputStreamReader的全部代码,很简单,都是在调用StreamDecode类中方法,StreamDecode是负责把读取的字节数据解码成字符数据的关键类。这个类好像是java官方的内部类,源码包中没有这个类,不过在这里可以查看。总之一句话,Reader、Writer就是把InputStream、OutputStream又装饰了一下,可以让程序方便的直接对字符读写。
字符流整体框架结构和字节流框架差不多,有一点值得注意:为什么BufferedReader不是FilterReader的子类,怎么直接继承了Reader?很简单,Reader这个类本身就是装饰类(这句话对么??)。
我用了一个星期才把IO框架理解到了这个程度,智商捉急,如有不对的地方,还望有大神能指正。
最后说明一下,这个框架图我是参考的别人的,稍作完善,尊重版权。参考博客
------- android培训、java培训、期待与您交流!
----------详情请查看:http://edu.csdn.net/heima
相关文章推荐
- 黑马程序员:管道流(PipedInputStream)介绍:IO和多线程结合的类
- DotText源码阅读(3)-框架配置体系和反序列化
- .net中的IO体系介绍
- Apache MINA 框架之IoService介绍
- 黑马程序员:Collections:集合框架工具类介绍及二分法原理介绍
- 网络编程模型综述 之 成熟的IO框架介绍
- UCML--编译型应用框架快速开发工具体系介绍
- Java_io体系之ByteArrayInputStream、ByteArrayOutputStream简介、走进源码及示例——04
- Servlet基础(一) Servlet简介 关键API介绍及结合源码讲解
- 黑马程序员:Java基础总结----集合与IO的结合[Properties类]
- 黑马程序员:Properties类介绍:集合中和IO技术相结合的集合容器
- .net中的IO体系介绍
- (转)网上流传的天龙源码框架分析之一 --- 客户端简单介绍
- (转)网上流传的天龙源码框架分析之一 --- 客户端简单介绍
- 黑马程序员—多线程聊天室(Socket介绍+源码)
- Servlet框架基础和生命周期(结合源码)、destroy()的思考
- .net中的IO体系介绍
- 网上流传的天龙源码框架分析之一 --- 客户端简单介绍
- 【转】网络编程模型综述 之 成熟的IO框架介绍
- 黑马程序员 14 Java基础教学 - 14 - IO体系总结01