Java PushbackReader
当我们从Reader解析数据时,应使用Java PushbackReader类java.io.PushbackReader。有时,在确定如何解释当前字符之前,我们需要先阅读一些字符以查看即将出现的情况。 JavaPushbackReader
允许我们执行此操作。好吧,实际上,它允许我们将读取的字符推回"阅读器"中。这些字符将在我们下次调用read()
时再次读取。
JavaPushbackReader
的工作方式与PushbackInputStream
相似,不同之处在于PushbackReader
适用于字符,而PushbackInputStream
适用于字节。
PushbackReader示例
这是一个简单的" PushbackReader"示例:
PushbackReader pushbackReader = new PushbackReader(new FileReader("c:\data\input.txt")); int data = pushbackReader.read(); pushbackReader.unread(data);
对read()的调用与从其他Reader读取的字符一样,从PushbackReader读取一个字符。对unread()的调用将一个字符推回PushbackReader
中。下次调用read()时,将首先读取回退的字符。如果我们将多个字符推回" PushbackReader",则最新的推回字符将首先从" read()"方法返回,就像堆栈一样。
创建一个PushbackReader
要使用JavaPushbackReader
,必须首先创建PushbackReader
实例。我们可以使用" new"运算符,使用标准对象实例化来创建" PushbackReader"。必须将一个Java阅读器传递给PushbackReader
构造函数,PushbackReader
将从中读取其字符。这是创建JavaPushbackReader
的示例:
PushbackReader pushbackReader = new PushbackReader(new FileReader("c:\data\input.txt"));
这个例子将Java FileReader传递给PushbackReader
构造函数。这将使PushbackReader
从FileReader
中读取其字符。
设置PushbackReader的推回限制
我们可以在" PushbackReader"的构造函数中设置我们应该能够读取的字符数。这是使用PushbackReader
构造函数设置推回限制的方法:
int pushbackLimit = 8; PushbackReader reader = new PushbackReader( new FileReader("c:\data\input.txt"), pushbackLimit);
这个例子在PushbackReader
中设置了一个8个字符的内部缓冲区。这意味着我们一次最多只能读8个字符,然后再读一次。
读取字符
我们可以从JavaPushbackReader
中读取字符,就像从JavaReader
中读取字符一样,因为PushbackReader
是JavaReader
子类。换句话说,我们可以使用从Reader类继承的read方法。这是一个通过JavaPushbackReader
的read()
方法读取字符的示例:
int aChar = pushbackReader.read(); while(aChar != -1) { System.out.println((char) aChar); aChar = pushbackReader.read(); }
如上例所示,read()返回一个int,我们必须自己将该int强制转换为char。当" PushbackReader"中没有可用字符时," read()"方法将返回" int"值-1.
推回字符
要将字符推回Java" PushbackReader",必须调用其" unread()"方法。这是将字符推回PushbackReader
的示例:
int aChar = pushbackReader.read(); pushbackReader.unread(aChar); aChar = pushbackReader.read(); // reads character pushed back
本示例从" PushbackReader"读取一个字符,然后将其推回" PushbackReader",然后再次从" PushbackReader"读取该字符。
关闭PushbackReader
当我们从PushbackReader
中读取完字符后,我们应该记住将其关闭。关闭PushbackReader
也将关闭PushbackReader
正在读取的Reader
实例。
关闭" PushbackReader"是通过调用其close()
方法完成的。这是关闭PushbackReader
的样子:
pushbackReader.close();
我们还可以使用Java 7中引入的try-with-resources构造。这是如何使用try-with-resources构造使用和关闭" PushbackReader"外观的方法:
Reader reader = new FileReader("data/data.bin"); try(PushbackReader pushbackReader = new PushbackReader(reader)){ int data = pushbackReader.read(); while(data != -1) { System.out.print((char) data); data = pushbackReader.read(); } }
请注意,不再有任何显式的close()
方法调用。 try-with-resources构造可以解决这一问题。
还要注意,第一个FileReader
实例不是在try-with-resources块内创建的。这意味着try-with-resources块不会自动关闭此FileReader实例。但是,当关闭" PushbackReader"时,也会关闭其读取的" Reader"实例,因此当" PushbackReader"关闭时," FileReader"实例也将关闭。
解析范例
在本JavaPusbackReader
教程的最后,让我们看一个更详细的示例,说明在解析字符流时如何使用PushbackReader
。本示例对将从" PushbackReader"读取的下一个"令牌"的第一个字符进行采样,以确定下一个令牌的类型,然后将字符推回以供相应的令牌生成器读取。在这种情况下,该示例有点"结构化",这意味着在实际的解析器中,我们可能会做一些不同的事情。但是,该示例主要用于说明在真实的解析示例中如何使用" PushbackReader",而不是作为编写出色的解析器的教科书示例。
public class TextTokenizer { protected PushbackReader pushbackReader = null; public TextTokenizer(Reader reader) { this.pushbackReader = new PushbackReader(reader); } public String nextToken() { int firstChar = this.pushbackReader.read(); this.pushbackReader.unread(firstChar); if(((char)firstChar) == '"') { return readDoubleQuotedToken(); } if((char)firstChar) == '\'') { return readSingleQuotedToken(); } return readSingleWordToken(); } protected String readDoubleQuotedToken() { ... } protected String readSingleQuotedToken() { ... } protected String readSingleWordToken() { ... } }
这个例子有趣的部分是nextToken()
方法。该方法首先将" PushbackReader"中的字符读入变量,然后将读取的字符推回" PushbackReader"中。这样,nextToken()
方法就可以"采样"下一个令牌的第一个字符,并根据该值决定它是哪种令牌,以及调用哪种令牌的读取方法。
注意,对于单引号和双引号的标记,实际上没有必要将字符推回" PushbackReader",因为引号本身通常不包含在标记中。但是,对于readSingleTokenWord()来说,这是必需的,因为读取的字符是令牌值的第一个字符。
readDoubleQuotedToken(),readSingleQuotedToken()和readSingleWordToken()的实现已省略,以简化示例。想象一下,他们读取了用双引号("),单引号(')括起来的令牌或者以非单词字符结尾的令牌(例如空格,制表符,换行符等)。