15.4.4 推回输入流

15.4.4 推回输入流

在输入/输出流体系中,有两个特殊的流与众不同,就是PushbackInputStreamPushbackReader,它们都提供了如下三个方法

PushbackInputStream的unread方法

方法 描述
void unread(int b) 将一个字节推回到推回缓冲区里,从而允许重复读取刚刚读取的内容
void unread(byte[] b) 将一个字节数组内容推回到推回缓冲区里,从而允许重复读取刚刚读取的内容
void unread(byte[] b, int off, int len) 将一个字节数组里从off开始,长度为len字节的内容推回到推回缓冲区里,从而允许重复读取刚刚读取的内容。

PushbackReader的unread方法

方法 描述
void unread(int c) 将一个字符推回到推回缓冲区里,从而允许重复读取刚刚读取的内容
void unread(char[] cbuf) 将一个字符数组内容推回到推回缓冲区里,从而允许重复读取刚刚读取的内容
void unread(char[] cbuf, int off, int len) 将一个字符数组里从off开始,长度为len字节的内容推回到推回缓冲区里,从而允许重复读取刚刚读取的内容。

细心的读者可能已经发现了这三个方法与InputStreamReader中的三个read方法一一对应,没错,这三个方法就是PushbackInputStreamPushbackReader的奥秘所在。

推回缓冲区

read方法优先从退回缓冲器中读取

这两个推回输入流都带有一个推回缓冲区,当程序调用这两个推回输入流的unread方法时,系统将会把指定数组的内容推回到该缓冲区里,而**推回输入流每次调用read方法时总是先从推回缓冲区读取,只有完全读取了推回缓冲区的内容后,但还没有装满read所需的数组时才会从原输入流中读取**。图15.10显示了这种推回输入流的处理示意图。
这里有一张图片
根据上面的介绍可以知道,当程序创建一个PushbackInputStreamPushbackReader时需要指定推回缓冲区的大小,默认的推回缓冲区的长度为1。如果程序中推回到推回缓冲区的内容超出了推回缓冲区的大小,将会引发Pushback buffer overflowIOException异常。
虽然图15.10中的推回缓冲区的长度看似比read方法的数组参数的长度小,但实际上,推回缓冲区的长度与read方法的数组参数的长度没有任何关系,完全可以更大。

程序示例

下面程序试图找出程序中的"new PushbackReader"这个字符串,当找到该字符串后,程序只是打印出目标字符串之前的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import java.io.*;

public class PushbackTest
{
public static void main(String[] args)
{
try(
// 创建一个PushbackReader对象,指定推回缓冲区的长度为64
PushbackReader pr = new PushbackReader(new FileReader(
"PushbackTest.java") , 64))
{
char[] buf = new char[32];
// 用以保存上次读取的字符串内容
String lastContent = "";
int hasRead = 0;
// 循环读取文件内容
while ((hasRead = pr.read(buf)) > 0)
{
// 将读取的内容转换成字符串
String content = new String(buf , 0 , hasRead);
int targetIndex = 0;
// 将上次读取的字符串和本次读取的字符串拼起来,
// 然后在拼接得到的字符串中查找目标字符串,
// 如果找到返回目标字符串开始的下标
if ((targetIndex = (lastContent + content)
.indexOf("new PushbackReader")) > 0)
{
// 将本次内容和上次内容一起推回缓冲区
pr.unread((lastContent + content).toCharArray());
// 重新定义一个长度为targetIndex的char数组
if(targetIndex > 32)
{
buf = new char[targetIndex];
}
// 再次 目标字符串下标 之前的内容(也就是不包括目标字符串的内容)
pr.read(buf , 0 , targetIndex);
// 打印目标字符串前面的内容
System.out.print(new String(buf , 0 ,targetIndex));
System.exit(0);
}
else
{
// 打印上次读取的内容
System.out.print(lastContent);
// 将本次内容设为上次读取的内容
lastContent = content;
}
}
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}
}

上面程序中将指定内容推回到推回缓冲区,于是当程序再次调用read()方法时实际上只是读取了推回缓冲区的部分内容,从而实现了只打印目标字符串前面内容的功能。
运行结果:

1
2
3
4
5
6
7
8
9
import java.io.*;

public class PushbackTest
{
public static void main(String[] args)
{
try(
// 创建一个PushbackReader对象,指定推回缓冲区的长度为64
PushbackReader pr =

PushbackReader其他方法

方法 描述
void close() Closes the stream and releases any system resources associated with it.
void mark(int readAheadLimit) Marks the present position in the stream.
boolean markSupported() Tells whether this stream supports the mark() operation, which it does not.
int read() Reads a single character.
int read(char[] cbuf, int off, int len) Reads characters into a portion of an array.
boolean ready() Tells whether this stream is ready to be read.
void reset() Resets the stream.
long skip(long n) Skips characters.

PushbackInputStream其他方法

方法 描述
int available() Returns an estimate of the number of bytes that can be read (or skipped over) from this input stream without blocking by the next invocation of a method for this input stream.
void close() Closes this input stream and releases any system resources associated with the stream.
void mark(int readlimit) Marks the current position in this input stream.
boolean markSupported() Tests if this input stream supports the mark and reset methods, which it does not.
int read() Reads the next byte of data from this input stream.
int read(byte[] b, int off, int len) Reads up to len bytes of data from this input stream into an array of bytes.
void reset() Repositions this stream to the position at the time the mark method was last called on this input stream.
long skip(long n) Skips over and discards n bytes of data from this input stream.