在 Java 里,FilterReader 类处于 java.io 包中,它是一个抽象类,继承自 Reader。该类的主要作用是为其他 Reader 提供一个过滤机制。FilterReader 类本身不执行任何过滤操作,它仅仅是作为一个基础,让开发者可以继承它并实现自定义的过滤逻辑。
FilterReader 包含一个受保护的 Reader 对象,该对象用于读取数据,而 FilterReader 则在这些数据被读取时进行过滤处理。通过继承 FilterReader,你能够创建自定义的过滤器,在读取字符流时对数据进行修改、转换或者选择性地读取。
下面是 FilterReader 的部分源码:
package java.io; public abstract class FilterReader extends Reader { // 底层字符输入流 protected Reader in; protected FilterReader(Reader in) { super(in); this.in = in; } public int read() throws IOException { return in.read(); } public int read(char cbuf[], int off, int len) throws IOException { return in.read(cbuf, off, len); } public long skip(long n) throws IOException { return in.skip(n); } public boolean ready() throws IOException { return in.ready(); } public boolean markSupported() { return in.markSupported(); } public void mark(int readAheadLimit) throws IOException { in.mark(readAheadLimit); } public void reset() throws IOException { in.reset(); } public void close() throws IOException { in.close(); } }
FilterReader 是一个基类,用于实现自己的过滤阅读器。基本上,它只是覆盖了 Reader 中的所有方法。
和 FilterInputStream 一样,我看不出该类有什么合理的用途。除了在构造函数中使用一个 Reader 之外,我看不出该类实际上增加或改变了 Reader 中的任何行为。如果你选择扩展该类,还不如直接扩展 Reader 类,避免在层次结构中增加额外的类。
以下是 FilterReader 的一些常见子类及其作用:
PushbackReader 允许你将已经读取的字符推回到输入流中,以便后续再次读取。这在进行词法分析、语法解析等场景中非常有用,因为在解析过程中可能会提前读取一些字符来判断后续的处理逻辑,但发现这些字符不适合当前的处理步骤,此时就可以将它们推回输入流,等待合适的时机再处理。
LineNumberReader 用于跟踪当前读取的行号。它在读取字符流时会自动记录行号,你可以通过调用 getLineNumber() 方法获取当前的行号。这在处理文本文件时非常有用,特别是在需要定位错误信息或进行调试时,能够方便地知道错误发生在哪一行。
虽然 BufferedReader 主要用于提供缓冲功能以提高读取效率,但它也间接继承自 FilterReader。它通过缓冲机制,一次从底层输入流读取一大块数据到缓冲区,然后从缓冲区中逐个字符地返回给调用者,减少了与底层输入流的交互次数,从而提高了读取性能。
StreamTokenizer 是一个特殊的 FilterReader 子类,用于将输入流解析为一系列的标记(token)。它可以识别不同类型的标记,如单词、数字、标点符号等,并将输入流按照标记进行分割。这在进行文本处理、词法分析等场景中非常有用。
下面为你展示一个自定义 FilterReader 的示例,该示例会过滤掉输入文本里的所有小写字母:
package com.hxstrive.java_io; import java.io.FilterReader; import java.io.IOException; import java.io.Reader; import java.io.StringReader; // 自定义 FilterReader 类,继承自 FilterReader class CustomFilterReader extends FilterReader { // 构造函数,接收一个 Reader 对象 protected CustomFilterReader(Reader in) { super(in); } // 重写 read() 方法,过滤小写字母 @Override public int read() throws IOException { int c; // 循环读取字符,直到遇到非小写字母或文件结束 while ((c = super.read()) != -1) { if (!Character.isLowerCase(c)) { return c; } } return -1; } // 重写 read(char[] cbuf, int off, int len) 方法 @Override public int read(char[] cbuf, int off, int len) throws IOException { int numChars = super.read(cbuf, off, len); if (numChars == -1) { return -1; } int pos = off; for (int i = off; i < off + numChars; i++) { if (!Character.isLowerCase(cbuf[i])) { cbuf[pos++] = cbuf[i]; } } return pos - off; } public static void main(String[] args) { String input = "Hello, World! 123"; // 创建一个 StringReader 对象,用于读取输入字符串 try (StringReader sr = new StringReader(input); // 创建自定义的 FilterReader 对象 CustomFilterReader cfr = new CustomFilterReader(sr)) { int c; // 循环读取过滤后的字符并输出 while ((c = cfr.read()) != -1) { System.out.print((char) c); } } catch (IOException e) { e.printStackTrace(); } //输出: //H, W! 123 } }
注意,CustomFilterReader 类继承自 FilterReader,重写了 read() 和 read(char[] cbuf, int off, int len) 方法。在 read() 方法里,它会持续读取字符,直至遇到非小写字母或者文件结束。在 read(char[] cbuf, int off, int len) 方法中,它会过滤掉字符数组里的小写字母。
在 main() 方法中,创建了一个 StringReader 对象来读取输入字符串,接着创建 CustomFilterReader 对象对输入进行过滤,最后把过滤后的字符输出。