Java IO - CharArrayReader&CharArrayWriter

基本概念

  • CharArrayReader:此类实现一个可用作字符输入流的字符缓冲区。

  • CharArrayWriter:此类实现一个可用作 Writer 的字符缓冲区。缓冲区会随向流中写入数据而自动增长。可使用 toCharArray() 和 toString() 获取数据。 在此类上调用 close() 无效,并且在关闭该流后可以调用此类中的各个方法,而不会产生任何 IOException。

-继承结构:分别继承了 Reader/Writer


源码分析

1.CharArrayReader

类结构结果图,通过与 ByteArrayInputStream 进行对比,发现 CharArrayReader 多了
ersureOpen(),ready() 少了一个 available(),且 ready 和 available 作用相似,通过下面的源码分析会发现二者的实现原理一模一样。

这里写图片描述

这里写图片描述

成员变量

//缓冲数组
protected char buf[];

//索引位置,表示当前读取的位置
protected int pos;

//标记位,只能标记当前读取的位置
protected int markedPos = 0;

//要读取的字符数组的长度
protected int count;

构造函数,结合成员变量的注释一目了然

public CharArrayReader(char buf[]) {
    this.buf = buf;
    this.pos = 0;
    this.count = buf.length;
}

public CharArrayReader(char buf[], int offset, int length) {
    if ((offset < 0) || (offset > buf.length) || (length < 0) || ((offset + length) < 0)) {
        throw new IllegalArgumentException();
    }
    this.buf = buf;
    this.pos = offset;
    this.count = Math.min(offset + length, buf.length);
    this.markedPos = offset;
}

先来看看多出来的 ensureOpen() 方法

//判断缓冲数组是否为空,作用就是字面上的意思确保字符流打开不为空,否则抛出异常
private void ensureOpen() throws IOException {
    if (buf == null){
        throw new IOException("Stream closed");
    }   
}

read 操作,这里实现了 Reader 中定义的抽象 read 方法,原理与字节数组输入流一模一样。

//读取单个字符
public int read() throws IOException {
    synchronized (lock) {
        ensureOpen();
        if (pos >= count)
            return -1;
        else
            return buf[pos++];
    }
}

//将字符读入数组的某一部分
public int read(char b[], int off, int len) throws IOException {
    synchronized (lock) {
        ensureOpen();
        if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return 0;
        }

        //根据索引位置,判断是否到达流末尾(即缓冲区末尾)
        if (pos >= count) {
            return -1;
        }

        //判断要读取的字符数量是否超出了缓冲数组中剩余的字符数量
        if (pos + len > count) {
            len = count - pos;
        }

        if (len <= 0) {
            return 0;
        }

        //重点-->将缓冲数组上的字符(从索引位置开始)复制到当前数组中
        System.arraycopy(buf, pos, b, off, len);

        pos += len;
        return len;
    }
}

skip 方法

表示要跳跃字符数量,通过改变数组的索引位置实现
public long skip(long n) throws IOException {
    synchronized (lock) {
        ensureOpen();
        if (pos + n > count) {
            n = count - pos;
        }
        if (n < 0) {
            return 0;
        }
        pos += n;
        return n;
    }
}

mark/reset 方法

//只能标记当前的读取位置,与参数值无关
public void mark(int readAheadLimit) throws IOException {
    synchronized (lock) {
        ensureOpen();
        markedPos = pos;
    }
}

public void reset() throws IOException {
    synchronized (lock) {
        ensureOpen();
        pos = markedPos;
    }
}

剩下的方法,只贴出源码,不做分析

public boolean markSupported() {
    return true;
}

public boolean ready() throws IOException {
    synchronized (lock) {
        ensureOpen();
        return (count - pos) > 0;
    }
}

//注意与字节写入流的区别
public void close() {
    buf = null;
}

2.CharArrayWriter

结构图,同样的与字节数组输出流没有大差别
这里写图片描述

这里写图片描述

成员变量,同上,不在阐述。

构造函数,不指定数组长度时默认 32

public CharArrayWriter() {
    this(32);
}

public CharArrayWriter(int initialSize) {
    if (initialSize < 0) {
        throw new IllegalArgumentException("Negative initial size: " + initialSize);
    }
    buf = new char[initialSize];
}

wirter 方法

//写入单个字符
public void write(int c) {
    synchronized (lock) {
        int newcount = count + 1;

        //判断下一次写入时长度如果超出缓冲数组的容量,则创建新的缓冲数组并将内容复制进去
        if (newcount > buf.length) {
            buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
        }
        buf[count] = (char) c;
        count = newcount;
    }
}

//写入字符数组的某一部分
public void write(char c[], int off, int len) {
    if ((off < 0) || (off > c.length) || (len < 0) || ((off + len) > c.length) || ((off + len) < 0)) {
        throw new IndexOutOfBoundsException();
    } else if (len == 0) {
        return;
    }
    synchronized (lock) {
        int newcount = count + len;
        if (newcount > buf.length) {
            buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
        }

        //关键-->写入操作,通过数组复制的方式
        System.arraycopy(c, off, buf, count, len);
        count = newcount;
    }
}

//写入字符串的某一部分
public void write(String str, int off, int len) {
    synchronized (lock) {
        int newcount = count + len;
        if (newcount > buf.length) {
            buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
        }
        str.getChars(off, off + len, buf, count);
        count = newcount;
    }
}

append 方法

//将指定字符添加到此 writer,并返回此 writer
public CharArrayWriter append(CharSequence csq) {
    String s = (csq == null ? "null" : csq.toString());
    write(s, 0, s.length());
    return this;
}

//将指定字符序列添加到此 writer,并返回此 writer
public CharArrayWriter append(CharSequence csq) {
    String s = (csq == null ? "null" : csq.toString());
    write(s, 0, s.length());
    return this;
}

//将指定字符序列的子序列添加到此 writer,并返回此 writer
public CharArrayWriter append(CharSequence csq, int start, int end) {
    String s = (csq == null ? "null" : csq).subSequence(start, end).toString();
    write(s, 0, s.length());
    return this;
}

剩余的方法,只贴出代码,不再探究

public char toCharArray()[] {
    synchronized (lock) {
        return Arrays.copyOf(buf, count);
    }
}

public String toString() {
    synchronized (lock) {
        return new String(buf, 0, count);
    }
}

public void writeTo(Writer out) throws IOException {
    synchronized (lock) {
        out.write(buf, 0, count);
    }
}

public int size() {
    return count;
}

public void reset() {
    count = 0;
}

public void flush() {
}

//注意与字节读取流的区别
public void close() {
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

oxf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值