Java I/O系统学习系列二:输入和输出

  编程语言的I/O类库中常使用流这个抽象概念,它表明任何有能力产出数据的数据源对象或者是有能力接收数据的接收端对象。“流”屏蔽了实际的I/O设备中处理数据的细节。html

  在这个系列的第一篇文章:<<Java I/O系统学习系列一:File和RandomAccessFile>>中,咱们讲到RandomAccessFile能够写入和读取文件,具有I/O功能,可是其只能针对文件,而I/O还涉及到不少其余场景好比网络、读取内存中的字符串等,因此Java类库中提供了一系列的类库来对其进行支持,也就是本文要总结学习的。编程

  Java类库中的I/O类分红输入和输出两部分,能够在JDK文档里的类层次结构中查看到。经过继承,任何自Inputstream或Reader派生而来的类都含有名为read()的基本方法,用于读取单个字节或者字节数组。一样,任何自OutputStream或Writer派生而来的类都含有名为write()的基本方法,用于写单个字节或者字节数组。可是,咱们一般不会用到这些方法,它们之因此存在是由于别的类可使用它们,以便提供更有用的接口。所以,咱们不多使用单一的类来建立流对象,而是经过叠合多个对象来提供所指望的功能(这是装饰器设计模式的应用,也有专门写文总结过:装饰器模式)。实际上,Java中“流”类库让人迷惑的主要缘由就在于:建立单一的结果流,却须要建立多个对象。设计模式

  I/O须要应对的场景每每是多样化的,Java类库的设计者则是经过建立大量的类来解决这个难题,区区一篇文章难以详述,本文也只是尽力对传统I/O类库所涉及到的类提供一个总览,在把握整个脉络的前提下才能更好的理解并应用I/O类库来解决实际编程问题。如需涉及到细节,仍是须要参考JDK文档。数组

  输入输出主要是字符流和字节流,本文主要从以下几个方面总结:网络

  InputStream/OutputStreamdom

  Reader/Writer编程语言

  总结学习

 

 

1. InputStream/OutputStream

  Java 1.0中,类库的设计者首先限定与输入有关的全部类都应该从InputStream继承,而与输出有关的全部类都应该从OutputStream继承。spa

1.1 InputStream

  InputStream的做用是用来表示那些从不一样数据源产生输入的类。这些数据源包括:设计

  • 字节数组;
  • String对象;
  • 文件;
  • “管道”,工做方式与实际管道类似,即从一端输入,从另外一端输出;
  • 一个由其余种类的流组成的序列,以便咱们能够将它们收集合并到一个流内;
  • 其余数据源,如Internet链接等;

   每一种数据源都有相应的InputStream子类,做为基础构件:

  • ByteArrayInputStream,容许将内存的缓冲区看成InputStream使用;
  • StringBufferInputStream,将String转换成InputStream;
  • FileInputStream,用于从文件中读取信息;
  • PipedInputStream,产生用于写入相关PipedOutputStream的数据。实现“管道化”概念;
  • SequenceInputStream,将两个或多个InputStream对象转换成单一InputStream;

1.2 OutputStream

  OutputStream的做用是表示那些能够输出到不一样数据源的类,其具体的子类决定了输出所要去往的目标:字节数组、文件或管道,一样是做为基础构件:

  • ByteArrayOutputStream,在内存中建立缓冲区。全部送往“流”的数据都要放置在此缓冲区;
  • FileOutputStream,用于将信息写至文件;
  • PipedOutputStream,任何写入其中的信息都会自动做为相关PipedInputStream的输出,实现“管道化”概念;

1.3 装饰器

  除了有上面的基础构件,还有两个子类:FilterInputStream/FilterOutputStream,也是InputStream和OutputStream的子类,它们为“装饰器”(decorator)类提供基类,其中,“装饰器”类能够把属性或有用的接口与基础构件链接在一块儿。由于上面提到的InputStream/OutputStream是单字节为单位来操做的,而真实的I/O场景远不止于此,因此就经过“装饰”(其原理是类之间的组合)的方式来扩展其功能。

  我本身梳理了一下InputStream/OutputStream流继承层次结构,结合下面的解释来看能够对字节流体系有一个更清晰的认识:

1.3.1 FilterInputStream

  FilterInputStream类主要有以下子类,也就是具体装饰器:

  • DataInputStream;
  • BufferedInputStream;
  • LineNumberInputStream;

  其提供的装饰功能主要在两个方面:

  • 读取不一样的基本类型数据以及String对象,好比DataInputStream;

  • 在内部修改InputStream的行为方式:是否缓冲、是否保留它所读过的行,如BuffereInputStream、LineNumberInputStream;

1.3.2 FilterOutputStream

  与FilterInputStream相似,FilterOutputStream主要是完成写入的功能,主要有以下装饰器:

  • DataOutputStream,与DataInputStream搭配使用,所以能够按照可移植方式向流中写入基本类型数据(int、char、long);
  • PrintStream,用于产生格式化输出。其中DataOutputStream处理数据的存储,PrintStream处理显示;
  • BufferedOutputStream,使用它以免每次发送数据时都要进行实际的写操做。表明“使用缓冲区”。能够调用flush()清空缓冲区;

   

2. Writer/Reader

  InputStream和OutputStream是提供面向字节形式的I/O,可是InputStream/OutputStream流继承层次结构仅支持8位字节流,而且不能很好地处理16位的Unicode字符。因为Unicode用于字符国际化(Java自己的char也是16位的Unicode),因此添加Reader/Writer继承层次结构就是为了在全部的I/O操做中都支持Unicode。

  几乎全部原始的Java I/O流类都有相应的Reader和Writer类来提供自然的Unicode操做,咱们能够对比一下:

  咱们发现大致上,这两个不一样的继承层次结构中的接口即便不能彻底相同,可是也是很是类似的。

  对于InputStream和OutputStream来讲,咱们会使用FilterInputStream和FilterOutputStream的装饰器子类来修改“流”以知足特殊须要。Reader/Writer的类继承层次结构继续沿用相同的思想,可是又并不彻底采用上面说到的装饰器模式。以下是本身梳理的Reader/Writer继承层次结构:

  与前面的I/O继承层次结构图相对比能够发现,尽管BufferedOutputStream是FilterOutputStream的子类,可是BufferedWriter并非FilterWriter的子类(FilterWriter是抽象类,可是没有任何子类,仅仅是做为一个占位符)。

2.1 适配器

  有时咱们必须把来自于“字节”层次结构中的类和“字符”层次结构中的类结合起来使用。为了实现这个目的,要用到“适配器”(adapter)类:InputStreamReader能够把InputStream转换为Reader,而OutputStreamWriter能够把OutputStream转换为Writer。

  

3. 总结

  • I/O须要应对的场景每每是多样化的,Java类库的设计者经过建立大量的类来解决这个难题,在实际使用中,经过装饰器模式避免“类爆炸”,但类的数量仍是很多,这也是Java中“流”类库让人迷惑的主要缘由;
  • InputStream和OutputStream是提供面向字节形式的I/O,而Reader和Writer则提供兼容Unicode与面向字符的IO功能;
  • 若是须要把字节流和字符流结合起来使用,可使用适配器进行转换,InputStreamReader能够把InputStream转换为Reader,而OutputStreamWriter能够把OutputStream转换为Writer;

   本文主要是梳理了传统I/O流的类继承层次结构,包括字节流(InputStream/OutputStream)和字符流(Writer/Reader),并无一开始就一头扎进I/O类库的海洋中,主要是但愿经过这种方式可以对整个I/O体系有一个清晰的认识,这对于进一步的学习能够有更明确的指导做用,下文会针对一些I/O的的典型使用方式进行总结。

相关文章
相关标签/搜索