3.1.4 过滤输入输出流

在基本的输入输出流之上,java.io包还提供了多种功能更强的过滤输入输出流。这些过滤流所提供的增强能力各不相同,比如前面提到的BufferedInputStream类和BufferedOutputStream类使用了内部的缓冲区来提高读写操作时的性能。另外一组过滤流DataInputStream类和DataOutputStream类在基本的字节流基础上提供了对读取和写入Java基本类型的支持。如果使用基本的字节流来操作Java中基本的整数、浮点数和字符串等类型的数据,需要开发人员自己完成这些数据类型与字节数组之间的转换工作。这个转换工作是平台相关的,并不是非常简单就能完成的。比如在读取和写入时需要考虑字节顺序,大端表示(big-endian)和小端表示(little-endian)的差别是很大的。在使用DataInputStream类时,可以通过readInt、readFloat和readUTF等方法来读取基本数据类型;在使用DataOutputStream类时,可以通过writeInt、writeFloat和writeUTF等方法来进行相应的写入操作。为了保证数据的正确性,对同样类型数据的写入和读取操作需要配对完成,这也是数据的提供者和消费者之间的契约。

除了读写基本数据类型的DataInputStream类和DataOutputStream类之外,ObjectInputStream类和ObjectOutputStream类在基本数据类型的基础上增加了读写Java对象的支持。可以把一个Java对象的内部状态写入到输出流中,还可以从输入流中直接创建Java对象。这是一种实用的对象持久化的实现方式。在第10章介绍Java对象序列化时,会深入讨论ObjectInputStream类和ObjectOutputStream类的使用。

在有些时候,当从输入流中读取了某些数据之后,希望把这些数据又放回输入流中,以便下次可以重新读取。这种重复读取的动机与3.1.3节中提到的流的复用并不相同。将数据放回输入流是为了实现流的前瞻功能。有些情况下,在处理流的时候需要查看流中当前剩下的内容以确定是否继续读取。如果不符合条件,就不能继续读取。为了查看这些内容,需要先读取到这些内容。但是一旦读取过了,再次读取的时候就无法获取到这些内容了,相当于有些内容丢失了。过滤流java.io.PushbackInputStream类可以解决这个问题,其中最关键的方法是unread,这个方法可以把一个或多个字节放回输入流中,下次再读取时,会首先读取被放回去的内容。