当前位置:文档之家› 输入输出流

输入输出流

第十章 输入/输出流程序在运行时通常要和外部进行交互, 即从外部读取数据或向外部设备发送数据, 这就 是所谓的输入/输出(Input/Output)。

数据可以来自或者发往文件、 内存、 另一个程序或网络。

数据也可有不同的格式,例如可以是各种编码(ASCII 码或 Unicode 码等)的字符串、图像、 声音或对象等等。

Java 语言使用抽象概念——流来描述程序与数据发送或接收者之间的数据 通道。

使用输入/输出流,程序员可以方便灵活和安全地实现输入输出功能。

§10.1 输入/输出基本概念10.1.1 外部设备与文件我们可以从不同角度对外部设备进行分类。

按照外部设备的工作特性, 我们可将外部设 备分为两类:存储设备和输入/输出设备。

存储设备用于存储信息,包括硬盘、软盘、磁带、光盘等。

程序可将数据写入到这些设 备上,也可从这些设备读出数据,数据通常组织为文件形式。

这类设备上存储的数据在物理 上往往是按字符块组织的,因而又将它们称为块设备。

输入/输出设备又可分为输入设备和输出设备。

输入设备是计算机用于接受外界信息的 设备,诸如键盘、鼠标、扫描仪等均为输入设备;输出设备是将计算机处理完毕的数据送往 外界的设备,诸如显示器、打印机、绘图仪等均为输出设备。

由于这两类设备上的数据往往 是以字符为单位组织的,所以又称它们为字符设备。

计算机程序要与外界进行交互就必须使用相应的机制与输入/输出设备打交道。

程序的 输入是指从输入设备接收数据,程序的输出是指将数据传递给外部设备。

早期的高级程序设计语言对特定的外部设备提供特定的输入/输出操作, 这导致设计出 来的程序代码可移植性很差。

后来引入了文件(file)的概念,在程序中不仅可以声明文件 并将文件作为输入/输出的对象, 而且还可以在文件与某个外部设备之间建立关联, 将文件 作为输入设备与输出设备的抽象描述。

目前文件已成为高级程序设计语言输入/输出机制的 基本概念。

一个文件必须有一个由用户命名的唯一名字。

文件可用于存储程序和数据, 还可用于提 高程序的设备无关性, 所谓设备无关性不仅指程序要独立于同类设备的具体台号, 而且还要 独立于设备的类型。

当我们的程序向屏幕或打印机输出时, 不必考虑使用的是哪一种型号的 显示器或打印机。

在操作系统中, 输入/输出设备被视作一种特殊的文件, 这类文件的名字是由操作系统 预先规定好的。

例如在 MS-DOS 中显示器被命名为 CON 的文件(控制台终端 console 的缩 写) 、打印机被命名为 PRN 的文件(printer 的缩写) 。

这样,程序的输入/输出操作采用了 与文件统一的方式,而不用理会实际的物理设备是什么。

10.1.2 文件的基本概念Java 语言将文件看作是字节的序列, 即由一个个字节的数据顺序组成。

例如我们要将一 个班全体学生的基本资料存放在一个文件中, 文件中的数据并不是由学生记录组成的, 而是 由一个个字节组成的。

如何将文件中的这些字节组织为记录是由程序完成的, 文件本身并没 有划定任何边界。

因而这种文件又称为流式文件(stream file) 。

(1)文本文件与二进制文件 根据文件中数据的组织形式, 可将文件分为文本文件和二进制文件两类。

文本文件存放 的是 ASCII 码(或其他编码的)字符,使用 Windows 操作系统的记事本打开可正确查看其-1-内容;而二进制文件可以是任何类型的文件,不能使用记事本类的文本编辑工具编辑。

通常 源程序代码是文本文件, 目标代码与可执行文件是二进制文件。

存放数据的文件既可设计为 文本文件,也可设计为二进制文件,应根据实际情况选择合适的方式。

(2)只读文件、只写文件与可读写文件 从访问文件中数据的存取控制方式来看, 文件的访问方式可设置为只读的、 只写的或可 读写的。

只读方式可保证原有文件中的内容不被破坏, 如果需要更新文件内容则必须采用只 写或可读写方式。

(3)顺序文件与随机文件 顺序文件是一个数据序列,对它的操作必须按照顺序进行,如打印机、磁带机等设备对 应的文件就是顺序文件。

随机文件的数据项可以通过地址直接访问,不必依照任何顺序,如 磁盘等设备对应的文件就是随机文件。

(4)文件缓冲 由于输入/输出外部设备的速度远低于计算机处理数据的速度, 所以文件系统一般都支 持缓冲(buffer)机制。

对于输出设备,程序输出的数据首先存放到一个开设在内存的缓冲 区中, 缓冲区中的数据装满后再整批送往外部设备。

将缓冲区数据送往外部设备的过程称为 刷新(flush) 。

对于输入设备,文件系统将数据整批读入到内存缓冲区中,程序中输入的数 据实际上取自缓冲区中, 缓冲区读完后才由文件系统读入下一批数据。

如果缓冲区的大小仅 有一个字符,则退化为无缓冲的情况。

10.1.3 输入/输出流程序与外部设备的交互作用通过操作系统(operating system)中的文件系统实现,文件 系统提供了一系列系统调用(system call)接口,程序利用这些接口与外界进行交互。

在使用一个文件之前必须先将它打开, 即通知操作系统为文件设置缓冲区并为程序分配 适当的设备;一旦文件使用完毕后必须将它关闭,这时相应的缓冲区将被释放,设备也与文 件脱离关联。

在使用文件的过程中可以使用各种形式的读/写操作。

但这些系统调用接口的层次太低, 在程序设计语言中直接使用这些系统调用太复杂且不 方便, 所以高级程序设计语言都提供了抽象层次更高的输入/输出机制。

Java 语言本身不包 含输入/输出语句,而是通过 Java API 提供的程序包 java.io 完成的。

为输入/输出数据, Java 程序与数据的发送者或接收者要建立一个数据通道, 这个数据 通道被抽象为流(stream),输入时 Java 程序是流的目标(destination)或潭(sink),输出时 Java 程序是流的源(source)。

流将输入/输出的源和目标分离开来, 程序在输出时只管将数据写入输出流, 而不管数 据到底写入到了哪个文件、设备或程序,在输入时只管从输入流读取数据,不管到底是从哪 个文件、设备或程序读取数据,输入/输出流负责关联到具体的文件、设备或程序。

程序对 各种流的处理也基本相同:打开流、读取/写入数据、关闭流,可以用统一的形式处理输入 /输出,这使得输入输出的编程变得简单和方便。

§10.2 Java 流系统概述Java API 提供了两套流类来处理输入/输出:一套是面向字节(byte-oriented)的流,一 套是面向字符(char-oriented)且基于 Unicode 编码的流。

面向字节的流以 8 位的字节为单位 处理输入输出数据,面向字符的流则以 16 位的字符为处理单位。

字节通常是计算机进行数 据处理的最小单位,面向字节的流可处理任何格式的数据,例如二进制文件,因为具体的格 式由程序自己负责解释。

面向字符的流则将输入输出的数据解释为基于 Unicode 编码的字 符,因此通常用于处理文本文件。

Java API 的每套流类都包括输入流类和输出流类, 这些流类按功能又都可分为与输入源 或输出目标相关联的基本流类和对输入输出功能进行装饰(decorate)的过滤器流类。

下面分小 节分别讨论其中的主要流类及它们之间的继承关系,从 10.3 节开始则以例子分类说明它们 的典型用法。

-2-10.2.1 面向字节的输入流类面向字节的输入流类都是类 InputStream 的后代类, InputStream 是根类 Object 的子类, 类 是对输入通道最基本功能的抽象。

类 InputStream 提供的主要方法见表 10.1,这些方法在该 类中虽然没有实质的实现, 但在后代类被重定义后将完成实质的输入功能, 程序员在使用输 入流时主要是使用类 InputStream 的后代类: 表 10.1 类 InputStream 的主要方法abstract int read() throws IOException 从流关联的输入源(调用构造方法创建对象实例时会将流关联到输入源)读入一个字节的数 据,成功则返回该数据,否则若遇到流的结尾返回-1,发生其它输入问题则抛出异常 IOException。

int read(byte[] buffer) throws IOException 从流关联的输入源试图读入 buffer.length 个字节的数据放到 buffer,除非碰到流的结尾或者 发生其他问题,如果至少成功读入一个字节的数据则返回读入数据的实际字节数,否则若遇到流 的结尾返回-1,发生其它输入问题则抛出异常 IOException,若 buffer 为 null 则抛出异常 NullPointerException。

调用该方法与调用 read(buffer, 0, buffer.length)等效。

int read(byte[] buffer, int offset, int length) throws IOException 从流关联的输入源试图读入 length 个字节的数据放到 buffer[offset]至 buffer[offset+length-1], 除非碰到流的结尾或者发生其他问题,如果至少成功读入一个字节的数据则返回读入数据的实际 字节数, 否则若遇到流的结尾返回-1, 发生其它输入问题则抛出异常 IOException, buffer 为 null 若 则抛出异常 NullPointerException,若 offset 或 length 为负数,或者 offset+length>buffer.length 则抛 出异常 IndexOutOfBoundsException。

void close() throws IOException 关闭流,释放与流关联的输入源。

类 InputStream 的主要子类及其完成的输入功能我们使用表 10.2 说明: 表 10.2 类 InputStream 的主要子类及其功能类名 ByteArrayInputStream FileInputStream 构造方法的主要参数 字节数组 byte[] buffer 类 File 的 对 象 、 类 FileDescriptor 的 对象或字符串表示的文 件名 PipedOutputStream 的对象 功能描述 以程序中的一字节数组作为输入源。

通常 用于对字节数组中的数据进行转换。

以文件作为输入源。

用于完成文件中数据 的输入操作。

辅助类 File 用于操纵文件 或文件目录(不操纵文件中的数据) 。

相关主题