推回输入流
在输入/输出流体系中,有两个特殊的流与众不同,就是PushbackInputStream和PushbackReader,它们都提供了如下三个方法。
-
void unread(byte[]/char[] buf):将一个字节/字符数组内容推回到推回缓冲区里,从而允许重复读取刚刚读取的内容。
-
void unread(byte[]/char[] b, int off, int len):将一个字节/字符数组里从off开始,长度为len字节/字符的内容推回到推回缓冲区里,从而允许重复读取刚刚读取的内容。
-
void unread(int b):将一个字节/字符推回到推回缓冲区里,从而允许重复读取刚刚读取的内容。
发现了这三个方法与InputStream和Reader中的三个read()方法一一对应,没错,这三个方法就是PushbackInputStream和PushbackReader的奥秘所在。
这两个推回输入流都带有一个推回缓冲区,当程序调用这两个推回输入流的unread()方法时,系统将会把指定数组的内容推回到该缓冲区里,而推回输入流每次调用read()方法时总是先从推回缓冲区读取,只有完全读取了推回缓冲区的内容后,但还没有装满read()所需的数组时才会从原输入流中读取。
根据上面的介绍可以知道,当程序创建一个PushbackInputStream和PushbackReader时需要指定推回缓冲区的大小,默认的推回缓冲区的长度为1。如果程序中推回到推回缓冲区的内容超出了推回缓冲区的大小,将会引发Pushback buffer overflow的IOException异常。
注意:
虽然图中的推回缓冲区的长度看似比read()方法的数组参数的长度小,但实际上,推回缓冲区的长度与read()方法的数组参数的长度没有任何关系,完全可以更大。
下面程序试图找出程序中的"new PushbackReader"字符串,当找到该字符串后,程序只是打印出目标字符串之前的内容。
public class PushbackTest {
public static void main(String[] args) {
try (
PushbackReader pushbackReader = new PushbackReader(new FileReader("src\\com\\rrz\\PushbackTest.java"), 64)
) {
int hasRead;
char[] chars = new char[32];
String lastContext = "";
while ((hasRead = pushbackReader.read(chars)) > 0) {
String context = new String(chars);
// 如果上次和这次拼接的字符串包含指定字符串,则推回
int index;
if ((index = (lastContext + context).indexOf("new PushbackReader")) > 0) {
// 推回
pushbackReader.unread((lastContext+context).toCharArray(), 0, index);
if (index > chars.length) {
chars = new char[index];
}
pushbackReader.read(chars, 0, index);
System.out.println(new String(chars, 0, index));
System.exit(0);
} else {
System.out.println(lastContext);
lastContext = context;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
上面粗体字代码实现了将指定内容推回到缓冲区,于是当程序再次调用 read()方法时,实际上只是读取了 推回缓冲区的部分内容,从而实现了只打印目标字符串前面内容的功能。
上一节:转换流
下一节:重定向标准输入标准输出