从JDK源码看Reader

作者:超人汪小建(seaboat)

出处:https://blog.csdn.net/wangyangzhizhou/column/info/16032


概况

Reader 是一个用于读字符流的抽象类,它将一些相通的读相关操作抽象到此类,方便各种读操作类的实现。一般来说子类只需要实现它的 read 和 close 两个方法,但如果有需要还可以重写 Reader 提供的公共方法。

JDK 在 Reader 的基础上实现了很多有用的 xxxReader ,包括 BufferedReader、CharArrayReader、FilterReader、InputStreamReader、FileReader、PipedReader、StringReader 和 LineNumberReader 等等。

继承结构

    --java.lang.Object
      --java.io.Reader

类定义

    public abstract class Reader implements Readable, Closeable

Reader 被定为 public 且 abstract 的类,实现了 Readable 和 Closeable接口。

Readable 接口表示尝试将字符读取到指定的缓冲中,接口定义如下:

    public interface Readable {
        public int read(java.nio.CharBuffer cb) throws IOException;
    }

Closeable 接口表示 Reader 可以被close,接口定义如下:

    public interface Closeable extends AutoCloseable {
        public void close() throws IOException;
    }

主要属性

    private static final int maxSkipBufferSize = 8192;

    private char skipBuffer[] = null;

    protected Object lock;
  • maxSkipBufferSize 最大跳过缓冲的大小。
  • skipBuffer 是一个 char[] 类型,表示跳过缓冲。
  • lock 是 Reader 的锁,用于实现同步。

构造方法

有两种构造方法,不带参数时则将自己作为锁,而如果传入了某个 Object 对象则将其作为锁。

    protected Reader() {
        this.lock = this;
    }
    protected Reader(Object lock) {
        if (lock == null) {
            throw new NullPointerException();
        }
        this.lock = lock;
    }

主要方法

read方法

一共有四个 read 方法,其中有一个抽象的 read 方法,可以看到所有 read 方法最终都会调用这个抽象方法,提供给子类处理逻辑的实现。它传入的三个参数,字符数组cbuf、偏移量off和数组长度。

    public abstract int read(char cbuf[], int off, int len) throws IOException;

无参的 read 方法其实是默认读一个字符,new 一个 char 对象然后调用子类实现进行读取,最后返回读到的字符。

    public int read() throws IOException {
        char cb[] = new char[1];
        if (read(cb, 0, 1) == -1)
            return -1;
        else
            return cb[0];
    }

假如 read 方法传入的参数为 char 数组时,则直接调用子类实现进行读取。

    public int read(char cbuf[]) throws IOException {
        return read(cbuf, 0, cbuf.length);
    }

最后一个 read 方法其实是 Readable 接口定义的方法,用于读取字符到指定的 CharBuffer 对象中,逻辑是先得到 CharBuffer 对象剩余长度,根据该长度实例化 char 数组,然后调用子类实现完成读取,最后将读取到的字符放进 CharBuffer 对象。

    public int read(java.nio.CharBuffer target) throws IOException {
        int len = target.remaining();
        char[] cbuf = new char[len];
        int n = read(cbuf, 0, len);
        if (n > 0)
            target.put(cbuf, 0, n);
        return n;
    }

ready方法

表示该读取器是否已准备好,默认返回 false,如果能保证调用 read 方法读取下一个字符不阻塞则返回 true。

    public boolean ready() throws IOException {
        return false;
    }

skip方法

该方法用于跳过指定长度字符,期间如果某些字符还未可读则可能发生阻塞,另外期间如果发生 IO 错误则会抛异常。逻辑是,
1. 跳过字符长度不能小于0。
2. 跳过长度不能超过最大跳过长度 maxSkipBufferSize,超过则只能取 maxSkipBufferSize。
3. 加锁开始处理,skipBuffer 对象如果为空则需要先实例化指定长度的 char 数组。
4. 不断循环调用子类的 read 方法进行读取,对读取到的字符不做处理,即实现了跳过效果。

    public long skip(long n) throws IOException {
        if (n < 0L)
            throw new IllegalArgumentException("skip value is negative");
        int nn = (int) Math.min(n, maxSkipBufferSize);
        synchronized (lock) {
            if ((skipBuffer == null) || (skipBuffer.length < nn))
                skipBuffer = new char[nn];
            long r = n;
            while (r > 0) {
                int nc = read(skipBuffer, 0, (int)Math.min(r, nn));
                if (nc == -1)
                    break;
                r -= nc;
            }
            return n - r;
        }
    }

close方法

它是一个抽象方法,留给子类实现。此方法用于关闭流,并且释放相关的资源 。关闭后再调用 read()、ready()、mark()、reset()或skip()等方法将抛出 IO 异常。

    public abstract void close() throws IOException;

markSupported方法

是否支持 mark 和 reset 操作,这里直接返回 false,子类根据实际重写该方法。

    public boolean markSupported() {
        return false;
    }

mark方法

标记读取器当前的位置,与之对应的是 reset 方法,通过他们之间的组合能实现重复读取操作。默认是不支持此操作的,需要子类重写该方法。

    public void mark(int readAheadLimit) throws IOException {
        throw new IOException("mark() not supported");
    }

reset方法

与 mark 方法对应,它可以重置读取器的位置到上次被 mark 操作标识的位置,如果未被标记过则可能会被重置到开始的位置。默认是不支持此操作的,需要子类重写该方法。

    public void reset() throws IOException {
        throw new IOException("reset() not supported");
    }
赞(0) 打赏

如未加特殊说明,此网站文章均为原创,转载必须注明出处。Java 技术驿站 » 从JDK源码看Reader
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

关注【Java 技术驿站】公众号,每天早上 8:10 为你推送一篇技术文章

扫描二维码关注我!


关注【Java 技术驿站】公众号 回复 “VIP”,获取 VIP 地址永久关闭弹出窗口

免费获取资源

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏