首先要记住Java有一个非常强大的 文件及目录类 File, 这里面你想要的功能都有。
下面进入正题。
由于JavaIO根据装饰器设计模式设计, 设计思想是先给出基本IO类,其他功能如缓存,格式化,再嵌套其他类实现。
在我看来实际上是个失败的设计,不仅没有使类变得简单,由于各种IO类必须组合起来才能发挥作用,反而增大了类的复杂度,写起来也冗余不已。
所以JavaIO类看起来会有些(非常)臃肿。
对于IO根据面向字符还是面向字节可分为两大类。
1. 面向字节的IO都是从InputStream和OutputStream继承而来。
提供对基本类型格式化IO基类是FilterInputStream(继承自InputStream)及FilterOutputStream(OutputStream),其中常用的主要有两个DataInputStream和DataOutputStream。
次外层常用的是BufferedInputStream及BufferedOutputStream主要是提供缓存功能。(其实我觉得这里用重载就挺好,没必要专门写两个类仅仅用来表示使用缓存)。
最里层是IO源类分别是ByteArrayInputStream, StringBufferInputStream, FileInputStream及相应的输出类。主要用于从数据源读取或输出。
好了下面我们来举个例子:
比如我们要从example.txt格式化写入数据。那么我们要这么写:
DataOutputStream in = new DataOutputStream( new BufferedOutputStream( new FileOutputStream("example.txt")));
读呢?
DataInputStream in = new DataInputStream( new BufferedInputStream( new FileInputStream("example.txt")));
当然这是个极端的例子,格式化输入输出的好处是可以实现对基本类型跨平台的格式化输入输出。
如果不追求这一点,一层就可以了。
FileInputStream in = new FileInputStream("example.txt");
in.read(); 每次读一个字符。但这样无缓存。
但这样比较慢,想快一点外面再前一层缓存 BufferedInputStream即可。
由于BufferedInputStream与DataInputStream是对输入流的深度处理,所以二者只接受InputStream类型。输出同理。
下面给出各个字节输入输出的继承结构:
InputStream -> FileInputStream,StringBufferInputStream 等
InputStream -> FilterInputStream -> DataInputStream及BufferedInputStream。
2. 面向字符的IO都是从Reader和Writer继承而来。
面向字符的操作与面向字节的操作类似。由于同样采用了装饰器模式,所以我们仍然需要记住所有的类才能写出一些简单而常用的功能。(失败)
最基本的源输入输出流: FileReader, FileWriter, StringReader, StringWriter, CharArrayReader, CharArrayWriter等。
如果想要提供缓存输入输出,嵌套: BufferedReader, BufferedWriter。
由于缓存是常用选项,所以Java IO 最少嵌套两层。设计的失败。
如果想控制台打印再嵌套 PrintWriter,这就嵌套了三层了。PrintWriter out = new PrintWriter( new BufferedWriter( new FileWriter( "file.txt")));
后来Java设计者也觉着这样有点过分。就在java SE5的时候给PrintWriter 添加了一个辅助构造器,可以接受String类型,实现上面三层嵌套的功能。 PrintWriter out = new PrintWriter("file.txt");
然而其他类,如缓存,仍需要我们手动嵌套两层。其实我不明白,像缓存这样常用功能,不应该是默认选项么。或者用函数重载来实现,这样我们添加一个参数就好,而不用用繁琐的嵌套。
所以JavaIO 体系可以看成滥用设计模式而导致失败的典型。
java NIO 重写了 FileInputStream, FileOutputStream以及RandomAccessFile这三个类,添加了通道(Channel)和缓存(ByteBuffer),以加快IO速度。不过java IO已用NIO重新实现过,所以IO 速度也变快了。