1、流(Stream)
stream代表的是任何有能力产出数据的数据源,或是任何有能力接收数据的接收源。Java的I/O操作类在java.io包下,这些类可以大概分为两类,操作字节流的和操作字符流的类:
- 字节流 表示以字节为单位从stream中读取或往stream中写入信息,即java.io包中的inputstream类和outputstream类的派生类。通常用来读取二进制数据,如图象和声音。
- 字符流 以Unicode字符为单位从stream中读取或往stream中写入信息。
2、字节输入流
下面来看一下操作字节输入流的类的框架结构:
由以上的类图可以看出:
- InputStream是所有的输入字节流的父类,它是一个抽象类。
- ByteArrayInputStream、StringBufferInputStream、FileInputStream是三种基本的介质流,它们分别从Byte数组、StringBuffer和本地文件中读取数据。PipedInputStream是从与其它线程共用的管道中读取数据。
- ObjectInputStream和所有FilterInputStream的子类都是装饰流。
各个类的详细的介绍如下:
在FilterInputStream类下还有一些具体的子类,如下图:
3、字节输出流
操作字节输出流的类的框架结构:
可以看到:
- OutputStream是所有的输出字节流的父类,它是一个抽象类。
- ByteArrayOutputStream、FileOutputStream是两种基本的介质流,它们分别向Byte数组和本地文件中写入数据。PipedOutputStream是向与其它线程共用的管道中写入数据。
- ObjectOutputStream和所有FilterOutputStream的子类都是装饰流。下表列出了输出字节流的功能及如何使用它们。
来看一下各个类的具体介绍:
在FilterOutputStream类下还有一些具体的子类,如下图所示。
4、字符输入流
从上图可以看出:
- Reader是所有的输入字符流的父类,它是一个抽象类。
- CharReader、StringReader是两种基本的介质流,它们分别将Char数组、String中读取数据。PipedReader是从与其它线程共用的管道中读取数据。
- BufferedReader很明显就是一个装饰器,它和其子类负责装饰其它Reader对象。
- FilterReader是所有自定义具体装饰流的父类,其子类PushbackReader对Reader对象进行装饰,会增加一个行号。
- InputStreamReader是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。FileReader可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream转变为Reader的方法。我们可以从这个类中得到一定的技巧。
5、字符输出流
在上面的关系图中可以看出:
- Writer是所有的输出字符流的父类,它是一个抽象类。
- CharArrayWriter、StringWriter是两种基本的介质流,它们分别向Char数组、String中写入数据。PipedWriter是向与其它线程共用的管道中写入数据,
- 是一个装饰器为Writer提供缓冲功能。
- PrintWriter和PrintStream极其类似,功能和使用也非常相似。
- OutputStreamWriter是OutputStream到Writer转换的桥梁,它的子类FileWriter其实就是一个实现此功能的具体类(具体可以研究一下Source Code)。功能和使用和OutputStream极其类似,后面会有它们的对应图。
6、字节流与字符流的区别
- Reader和Writer要解决的,最主要的问题就是国际化。原始的I/O类库只支持8位的字节流,因此不可能很好地处理16位的Unicode字符流。Unicode是国际化的字符集,这样加了Reader和Writer之后,所有的字节流都可以转换为字符流,也就都支持Unicode了。
- 使用字符处理要比字节处理的效率高。实际上字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的,而字符流在操作时使用了缓冲区,通过缓冲区再操作文件,如下图所示。同时缓冲区也增加了操作字符的灵活性,例如可以读取当前位置的前一个字符等等...
所以说某些情况下,如果一个程序频繁地操作一个资源(如文件或数据库),则性能会很低,此时为了提升性能,就可以将一部分数据暂时读入到内存的一块区域之中,以后直接从此区域中读取数据即可,因为读取内存速度会比较快,这样可以提升程序的性能。
OutputStreamWriter则将OutputStream转化成Writer。