Java IO源码分析(五)——CharArrayReader 和 CharArrayWriter

简介

CharArrayReader 是字符数组的输入流,它和我们之前讲的ByteArrayInputStream十分类似,顾名思义,区别在于一个用于字符数组,一个用于字节数组,在Java中字符是16位,而字节是8位的。

CharArrayReader 继承于Reader,操作的数据是以字符为单位。

源码分析

Reader

CharArrayReader 的抽象父类。

public abstract class Reader implements Readable, Closeable {
	// 对象锁,用于给读取和其他操作加锁
    protected Object lock;
	// 如果没有设置锁,那就讲对象锁设置为当前对象
    protected Reader() {
        this.lock = this;
    }
	// 传入锁的构造函数 
    protected Reader(Object lock) {
    	// 不能为空
        if (lock == null) {
            throw new NullPointerException();
        }
        this.lock = lock;
    }
	
	// 将缓存数据吸入目标字符缓存对象
    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;
    }

	// 读取一个字符
    public int read() throws IOException {
        char cb[] = new char[1];
        if (read(cb, 0, 1) == -1)
            return -1;
        else
            return cb[0];
    }

	// 读取字符数组长度的数据
    public int read(char cbuf[]) throws IOException {
        return read(cbuf, 0, cbuf.length);
    }
	
	// 子类需要实现的方法
    abstract public int read(char cbuf[], int off, int len) throws IOException;

    // 最大可跳跃读的长度
    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");

		// 计算跳跃的距离
        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;
        }
    }

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

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

    abstract public void close() throws IOException;

}

CharArrayReader

public class CharArrayReader extends Reader {
    // 存储字符数据的数组
    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;
    }

    // 检查是传入了数据
    private void ensureOpen() throws IOException {
        if (buf == null)
            throw new IOException("Stream closed");
    }

	// 同步读取一个字节
    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;
        }
    }

	// 跳过指定长度的缓存
    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;
        }
    }

	// 是否可用
    public boolean ready() throws IOException {
        synchronized (lock) {
            ensureOpen();
            // 是否还存在数据
            return (count - pos) > 0;
        }
    }

    public boolean markSupported() {
        return true;
    }

	// 标记当前读指针位置
    public void mark(int readAheadLimit) throws IOException {
        synchronized (lock) {
            ensureOpen();
            markedPos = pos;
        }
    }

	// 重置读指针的位置到之前标记的位置
    public void reset() throws IOException {
        synchronized (lock) {
            ensureOpen();
            pos = markedPos;
        }
    }
	// 关闭缓冲
    public void close() {
        buf = null;
    }
}

Writer

public abstract class Writer implements Appendable, Closeable, Flushable {
	// 写入缓冲
    private char[] writeBuffer;
	// 缓冲区的最大长度
    private static final int WRITE_BUFFER_SIZE = 1024;
	// 锁对象
    protected Object lock;

    protected Writer() {
        this.lock = this;
    }

    protected Writer(Object lock) {
        if (lock == null) {
            throw new NullPointerException();
        }
        this.lock = lock;
    }
	// 写入一个字符
    public void write(int c) throws IOException {
        synchronized (lock) {
            if (writeBuffer == null){
                writeBuffer = new char[WRITE_BUFFER_SIZE];
            }
            writeBuffer[0] = (char) c;
            write(writeBuffer, 0, 1);
        }
    }
	// 写入字符数组
    public void write(char cbuf[]) throws IOException {
        write(cbuf, 0, cbuf.length);
    }
	// 写入指定位置的数组,子类实现
    abstract public void write(char cbuf[], int off, int len) throws IOException;

    public void write(String str) throws IOException {
        write(str, 0, str.length());
    }
	// 写入指定字符串
    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.getChars(off, (off + len), cbuf, 0);
            write(cbuf, 0, len);
        }
    }

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


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

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

    abstract public void flush() throws IOException;


    abstract public void close() throws IOException;

}

CharArrayWriter

public
class CharArrayWriter extends Writer {
	// 写入缓存区
    protected char buf[];
	// 缓存区可用数据长度
    protected int count;

	// 默认长度是32
    public CharArrayWriter() {
        this(32);
    }

	// 初始化缓存区长度的构造
    public CharArrayWriter(int initialSize) {
        if (initialSize < 0) {
            throw new IllegalArgumentException("Negative initial size: "
                                               + initialSize);
        }
        buf = new char[initialSize];
    }

	// 写入一个字符
    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;
        }
    }

	// 写入到其他的Writer 对象
    public void writeTo(Writer out) throws IOException {
        synchronized (lock) {
            out.write(buf, 0, count);
        }
    }

	// 写入一个CharSequence ,返回CharArrayWriter 对象
    public CharArrayWriter append(CharSequence csq) {
        String s = (csq == null ? "null" : csq.toString());
        write(s, 0, s.length());
        return this;
    }

    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 CharArrayWriter append(char c) {
        write(c);
        return this;
    }
	// 重置当前对象的缓存状态
    public void reset() {
        count = 0;
    }

	// 幻化为数组输出
    public char toCharArray()[] {
        synchronized (lock) {
            return Arrays.copyOf(buf, count);
        }
    }

	// 获取缓存区大小
    public int size() {
        return count;
    }

	// 转化为字符串
    public String toString() {
        synchronized (lock) {
            return new String(buf, 0, count);
        }
    }

    public void flush() { }

    public void close() { }

}

总结

CharArrayReader

  • CharArrayReader实际上是通过“字符数组”来保存数据的。
  • 创建对象的时候需要传入字符数组作为缓存区数据。
  • 它也具有标记跳跃功能,就是先标记当前的位置,再跳跃到后面读后面的数据,然后根据标志位置再回来读前面的数据。
  • 和ByteArrayInputStream另一个不同点是,ByteArrayInputStream的同步关键词修饰的是操作方法,意味着ByteArrayInputStream的操作需要获取当前的对象锁,而CharArrayReader中的同步关键词修饰的是对象,锁对象可以通过外部传入,如果没有传入,那就默认为当前对象,所以,CharArrayReader的同步方式更具灵活性。

CharArrayWriter

  • CharArrayWriter实际上是将数据写入到“字符数组”中去。
  • 默认的缓冲区大小是32,之后可以进行扩容,默认的扩容长度是两倍。
  • write和append方法都能进行添加函数,不同的是,前者什么都不返回,而后者返回当前CharArrayWriter对象。
原文地址:https://www.cnblogs.com/lippon/p/14131637.html