zoukankan      html  css  js  c++  java
  • 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对象。
  • 相关阅读:
    POJ 1436 Horizontally Visible Segments(线段树)
    POJ 1436 Horizontally Visible Segments(线段树)
    精益项目管理的可行性分析
    精益项目管理的可行性分析
    精益项目管理的可行性分析
    精益项目管理的可行性分析
    单点登录cas常见问题(二)
    单点登录cas常见问题(二)
    蓝氏兄弟依靠板栗东山再起,意外赚回八九万元
    元旦快乐,感谢一路相伴!
  • 原文地址:https://www.cnblogs.com/lippon/p/14131637.html
Copyright © 2011-2022 走看看