在 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 对象对输入进行过滤,最后把过滤后的字符输出。