Java中IO框架——Reader/Writer源码解析

本文详细探讨了Java中的IO框架,重点关注Reader和Writer类。分析了Reader类的构造函数、属性和核心方法,如read()、skip()、ready()及close()等。同时,介绍了Writer类的相似功能,包括write()、flush()和close()。通过对这两个类的源码解析,有助于理解Java字符流的操作机制。

Reader

属性

    // 用于同步针对此流的操作的对象。
    protected Object lock;

构造函数

两个构造函数,使用不同的对象锁。

    // 创建一个新的字符流 reader,其重要部分将同步其自身的 reader。
    protected Reader() {
        this.lock = this;
    }
    // 创建一个新的字符流 reader,其重要部分将同步给定的对象。
    protected Reader(Object lock) {
        if (lock == null) {
            throw new NullPointerException();
        }
        this.lock = lock;
    }

方法

read(char cbuf[], int off, int len)

将字符读入缓冲数组 cbuf 中,从 off 下标开始存放,共 len 个字符。

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

read()

读取单个字符。

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

read(char cbuf[])

调用上边的 read 方法,从下标 0 处开始存入。

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

read(java.nio.CharBuffer target)

试图将字符读入指定的字符缓冲区。

    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;
    }

skip(long n)

跳过字符。

    // 最大可跳过缓冲字符的值8192
    private static final int maxSkipBufferSize = 8192;
    // 跳过的字符数组
    private char skipBuffer[] = null;

    public long skip(long n) throws IOException {
        if (n < 0L)
            // 跳过的字符数不能为负
            throw new IllegalArgumentException("skip value is negative");
        // 跳过的字符数量nn,取需求n和最大可跳过之间的较小值
        int nn = (int) Math.min(n, maxSkipBufferSize);
        // 同步对象锁
        synchronized (lock) {
            // 如果跳过数组为空或者长度小于目标跳过的数量nn,重建跳过数组长度为nn
            if ((skipBuffer == null) || (skipBuffer.length < nn))
                skipBuffer = new char[nn];
            long r = n;
            // 如果正常情况下,跳过n个,r最终是为0的
            // 如果遇到末尾没有那么多字符可以跳过,那么r就是剩余不能跳过的,实际跳过n-r个
            while (r > 0) {
                int nc = read(skipBuffer, 0, (int)Math.min(r, nn));
                if (nc == -1)
                    break;
                r -= nc;
            }
            return n - r;
        }
    }

ready()

判断是否准备读取此流。

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

mark/reset

不支持 mark 和 reset 。

    public boolean markSupported() {
        return false;
    }
    public void mark(int readAheadLimit) throws IOException {
        throw new IOException("mark() not supported");
    }
    public void reset() throws IOException {
        throw new IOException("reset() not supported");
    }

close()

关闭该流并释放与之关联的所有资源。在关闭该流后,再调用 read()、ready()、mark()、reset() 或 skip() 将抛出 IOException。关闭已经关闭了的流无效。

    abstract public void close() throws IOException;

Writer

写入字符流的抽象类。

属性

    // 临时的字符数组保存写入的字符
    private char[] writeBuffer;
    // 临时字符数组的大小1024
    private static final int WRITE_BUFFER_SIZE = 1024;
    // 用于同步针对此流的操作的对象
    protected Object lock;

构造函数

和 Reader 的两个构造函数类似,两个构造函数区别在于用什么对象锁,自身还是其他对象。

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

方法

write(char cbuf[], int off, int len)

将字符数组 cbuf 中的字符写入输出流,从下标 off 开始,共 len 个字符。

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

write(int c)

写入单个字符。要写入的字符包含在给定整数值的 16 个低位中,16 高位被忽略。

    public void write(int c) throws IOException {
        synchronized (lock) {
            if (writeBuffer == null){
                writeBuffer = new char[WRITE_BUFFER_SIZE];
            }
            // 字符2个字节,int是4个字节丢弃高位的2个,保留低位2个存入临时字符数组
            writeBuffer[0] = (char) c;
            // 调用上边的write方法,写进输出流1个字符
            write(writeBuffer, 0, 1);
        }
    }

write(char cbuf[])

字符数组 cbuf 中写入输出流,调用上边的 write 方法。

    public void write(char cbuf[]) throws IOException {
        write(cbuf, 0, cbuf.length);
    }

write(String str, int off, int len)

字符串写入输出流。

    public void write(String str, int off, int len) throws IOException {
        synchronized (lock) {
            char cbuf[];
            if (len <= WRITE_BUFFER_SIZE) {
                if (writeBuffer == null) {
                    writeBuffer = new char[WRITE_BUFFER_SIZE];
                }
                cbuf = writeBuffer;
            } else {    // Don't permanently allocate very large buffers.
                cbuf = new char[len];
            }
            // 将字符串str从off开始共len个字符存入cbuf字符数组中
            str.getChars(off, (off + len), cbuf, 0);
            // cbuf从0下标开始len个字符写进输出流
            write(cbuf, 0, len);
        }
    }

write(String str)

    public void write(String str) throws IOException {
        // 调用上边的write方法
        write(str, 0, str.length());
    }

append(CharSequence csq)

将指定字符序列添加到此 writer。

    public Writer append(CharSequence csq) throws IOException {
        if (csq == null)
            write("null");
        else
            write(csq.toString());
        return this;
    }

append(CharSequence csq, int start, int end)

将指定字符序列的子序列添加到此 writer

    public Writer append(CharSequence csq, int start, int end) throws IOException {
        CharSequence cs = (csq == null ? "null" : csq);
        write(cs.subSequence(start, end).toString());
        return this;
    }

append(char c)

将指定字符添加到此 writer。

    public Writer append(char c) throws IOException {
        write(c);
        return this;
    }

flush()

刷新该流的缓冲。如果该流已保存缓冲区中各种 write() 方法的所有字符,则立即将它们写入预期目标。然后,如果该目标是另一个字符或字节流,则将其刷新。因此,一次 flush() 调用将刷新 Writer 和 OutputStream 链中的所有缓冲区。

    abstract public void flush() throws IOException;

close()

关闭此流,但要先刷新它。在关闭该流之后,再调用 write() 或 flush() 将导致抛出 IOException。关闭以前关闭的流无效。

    abstract public void close() throws IOException;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值