Java: I/O(1/3)字节流与字符流的纵向与横向比较

Summary 总述

java.io包中的类很是繁多,但其实只要归成4类:InputStream & OutputStreamReader & Writer,因为功能和命名上都至关接近,所以只要掌握了其中一种,将会很容易理解其余3种。java

横向归类:InputStream & OutputStream(字节流)、Reader & Writer(字符流).
纵向归类:InputStream做为父类,其子类的角色和做用,并以此触类旁通。api

字节流

字节(byte)是计算机中基本数据单位,一切的计算机数据(或“文件”)都是由或多或少的字节组成,所以使用字节流,理论上能够处理一切计算机数据(文件),包括图像、音频、文本等。数组

然而对于文本数据,因为存在编码问题比较麻烦,因此交由字符流处理。oracle

字符流

1char=2byte,字符(char)的表示范围(2^16)是字节(byte)表示范围(2^8)的2^8=256倍。专门用于处理文本数据。dom

历史

字节流在Java的第一版(jdk 1.0)已经存在,字符流在jdk 1.1中加入,以替代字节流中处理字符的功能。性能

装饰者模式

私觉得,提到Java I/O的话,不能不提装饰者模式ui

装饰者模式就是在一个主体(被装饰者)的外部使用装饰类来进行装饰,对主体的行为根据不一样的装饰者类进行不一样的修改。单个的装饰类自根据自身特色对主体的行为进行部分改进,所以能够组合多个装饰类来对主体进行修改(在代码中表现为多层装饰类的嵌套)。编码

Java的I/O类设计应用了装饰者模式。单个的流对象主体,例如InputStream的直接子类(Direct Subclasses)中,分别面向文件FileInputStream、内存ByteArrayInputStream、线程PipedInputStream,而InputStream的另外一个直接子类FileterInputStream为装饰类(的父类),分别定义了各类具体的装饰类(如BufferedInputStreamDataInputStream等)。线程

如图: Alt text设计

从代码的角度来看:DataInputStreamBufferedInputStream为装饰者,FileInputStream为主体(被装饰者)

InputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(new File(src))));

装饰者模式从抽象的角度来讲很容易理解,然而也存在一个很明显的缺点:装饰类过多。所以咱们能看到java.io包中那么多的类。若是没有理解装饰者模式,即便有必定经验的Java developer也会感到混乱。

结论

  • 处理非文本数据使用字节流;
  • 处理具体的文本数据使用字符流;

例如对于文件复制这样的操做来讲,即便是文本文件的复制,咱们对其具体的内容是什么并不关心,所以能够直接使用字节流。但当咱们要从一个文本文件中读取内容,咱们关心其具体的内容,因此使用字符流。


Description 详细内容

篇幅所限,只列出经常使用的类,其他部分可参考Java API手册

继承关系图

Alt text

字节流的继承关系

OutputStream

  • OutputStream
    • ByteArrayOutputSteam:将数据输出到字节数组(byte array)中,也就是内存,不用生成文件;
    • FileOutputStream:将数据输出到具体的文件;
    • PipedOutputStream:将数据输出到线程,即经过与PipedInputStream联合使用,将数据在不一样的线程之间传递;
    • FilterOutputStream:装饰类的父类
      • BufferedOutputStream:使用了缓冲区,调用flush()才会清空缓冲区将数据写入文件。与普通OutputStream相比,因为不用频繁地与文件进行I/O数据传输(内存与磁盘之间,这将消耗大部分性能),而是在每次调用flush()时一次性地将一块数据在内存与磁盘中传输,所以会性能将获得提高(有NIO的影子);
      • DataOutputStream:用于方便地传输基础类型的数据,所以除了传统的write()外,还有一堆writeInt()、writeDouble、writeBoolean()等;
      • PrintStream:InputStream原本是适合用于非文本的二进制文件(如图片、声音文件等),而PrintStream则是在字节流中专门用于打印文本内容;

InputStream

  • InputStream
    • ByteArrayInputStream:从内存中读取数据;
    • FileInputStream:从文件中读取数据;
    • PipedInputStream:从一个线程中读取数据,从另外一个线程中输出(PipedOutputStream),同一线程下使用者两个对象可能会形成线程死锁;
    • SequenceInputStream:将两个InputStream合并成一个;
    • FilterInputStream:装饰类的父类;
      • BufferedInputStream:使用了缓冲区,参考BufferedOutputStream
      • DataInputStream:方便地读取基本类型的数据,所以除了基础的read()外,还有一堆readChar()、readDouble()、readInt()等;

字符流的继承关系

Writer

  • BufferedWriter:缓冲区;
  • CharArrayWriter:面向内存;
  • PipedWriter:面向线程;
  • PrintWriter:方便输出,特别是按格式输出printf();
  • StringWriter:使用StringBuilder来存放内容;
  • OutputStreamWriter:用于字符流与字节流之间的转换;
    • FileWriter:面向文件
  • FilterWriter:装饰类

Reader

  • BufferedReader:缓冲区;
  • CharArrayReader:面向内存;
  • PipedReader:面向线程;
  • InputStreamReader:用于字符流与字节流之间的转换;
    • FileReader:面向文件
  • FilterReader

Others 其余

本篇做为Java I/O系列之一,只分析了字节流和字符流。其余Java I/O内容如File、RandomAccessFile、System类的I/O支持和重定向、字符编码、文件压缩、对象序列化和Scanner等内容会在(2/3)中发表。

NIO部分打算在(3/3)中发表。

相关文章
相关标签/搜索