Java流的概念

输入输出(I/O)是指程序与外部设备或其他计算机进行交互的操作。几乎所有的程序都具有输入与输出操作,如从键盘上读取数据,从本地或网络上的文件读取数据或写入数据等。通过输入和输出操作可以从外界接收信息,或者是把信息传递给外界。

Java 把这些输入与输出操作用流(Stream)来实现,通过统一的接口来表示,从而使程序设计更为简单。

Java流的概念

流(Stream)是指在计算机的输入输出操作中各部件之间的数据流动,按照数据的传输方向,流可分为输入流与输出流。

Java 语言里的流序列中的数据既可以是未经加工的原始二进制数据,也可以是经过一定编码处理后符合某种特定格式的数据。

1) 输入输出流

在 Java 中,把不同类型的输入输出源抽象为流,其中输入和输出的数据称为数据流(Data Stream)。数据流是 Java 程序发送和接收数据的一个通道,数据流中包括输入流(Input Stream)和输出流(Output Stream)。

输入输出时相对程序来说的,输出流是往存储介质或数据通道(文件、键盘、网络等)写入数据,而输入流是从存储介质或数据通道中读取数据。

流式输入输出的特点是数据的获取和发送均沿数据序列顺序进行,一般来说有以下几点特性:
  • 先进先出,最先写入输出流的数据最先被输入流读取到。
  • 顺序存取,可以一个接一个地往流中写入一串字节,读出时也将按写入顺序读取一串字节,不能随机访问中间的数据。
  • 只读或只写,每个流只能是输入流或输出流的一种,不能同时具备两个功能,在一个数据传输通道中,如果既要写入数据,又要读取数据,则要分别提供两个流。

2) 缓冲流

为了提高数据的传输效率,引入了缓冲流(Buffered Stream)的概念,即为一个流配备一个缓冲区(Buffer)。所谓缓冲区,就是专门用于传送数据的一块内存。

关于缓冲区的说明:
  • 当向一个缓冲流写入数据时,系统将数据发送到缓冲区,而不是直接发送到外部设备。缓冲区自动记录数据,当缓冲区满时,系统将数据全部发送到相应的外部设备。
  • 当从一个缓冲流中读取数据时,系统实际是从缓冲区中读取数据,当缓冲区为空时,系统就会从相关外部设备自动读取数据,并读取尽可能多的数据填满缓冲区。

总结

使用数据流来处理输入输出的目的是使程序的输入输出操作独立于相关设备,由于程序不需关注具体设备实现的细节(具体细节由系统处理),所以对于各种输入输出设备,只要针对流做处理即可,不需修改源程序,从而增强了程序的可移植性。

流类简介

为了方便流的处理,Java 语言提供了 java.io 包,在该包中的每一个类都代表了一种特定的输入或输出流。为了使用这些流类,编程时需要引入这个包。

Java 提供了两种类型的输入输出流:
  • 一种是面向字节的流(字节流),数据的处理以字节为基本单位;
  • 一种是面向字符的流(字符流),用于字符数据的处理。

字节流(Byte Stream)每次读写 8 位二进制数,也称为二进制字节流或位流。字符流一次读写 16 位二进制数,并将其做一个字符而不是二进制位来处理。

需要注意的是,为满足字符的国际化表示,Java 语言的字符编码采用的是 16 位的 Unicode 码,而普通文本文件中采用的是 8 位 ASCII 码。

java.io 中类的层次结构如下图所示:
图10-1 java.io包的顶级层次结构图
图1:java.io 包的顶级层次结构图

针对一些频繁的设备交互,Java 语言系统预定了 3 个可以直接使用的流对象,分别是:
  • System.in(标准输入),通常代表键盘输入。
  • System.out(标准输出):通常写往显示器。
  • System.err(标准错误输出):通常写往显示器。

在 Java 语言中使用字节流和字符流的步骤基本相同,以输入流为例,首先创建一个与数据源相关的流对象,然后利用流对象的方法从流输入数据,最后执行 close() 方法关闭流。