Java8 I/O源码-CharArrayReader与CharArrayWriter

前两篇文章Java8 I/O源码-Reader与Writer简单介绍了Reader和Writer。本文将详细介绍CharArrayReader与CharArrayWriter,拉开学习字符型输入流的序幕。

CharArrayReader实现一个可用作字符输入流的字符缓冲区。支持mark/set。

CharArrayWriter实现一个可用作字符输出流的字符缓冲区。缓冲区会随向流中写入数据而自动增长。可使用 toCharArray()和 toString()获取数据。

CharArrayReader

public class CharArrayReader extends Reader {
    /** 字符缓冲区 */
    protected char buf[];

    /** 缓冲区中下一个被获取的字符的索引 */
    protected int pos;

    /** The position of mark in buffer. */
    protected int markedPos = 0;

    /** 字符缓冲区大小 **/
    protected int count;

    /**
     * 根据指定的char数组创建一个CharArrayReader。
     * 
     * buf不是复制得到的
     */
    public CharArrayReader(char buf[]) {
        this.buf = buf;
        this.pos = 0;
        this.count = buf.length;
    }

    /**
     * 根据指定的char数组创建一个CharArrayReader。
     *
     * @throws IllegalArgumentException 如果offset为负或大于buf.length,或者length为负,或者这两个值的和为负。
     *
     * @param buf       输入缓冲区(不是复制得到的)
     * @param offset    要读取的第一个char在buf中的索引/偏移量
     * @param length    要读取的char数目
     */
    public CharArrayReader(char buf[], int offset, int length) {
        //如果offset为负或大于buf.length,或者length为负,或者这两个值的和为负,抛出IllegalArgumentException。
        if ((offset < 0) || (offset > buf.length) || (length < 0) ||
            ((offset + length) < 0)) {
            throw new IllegalArgumentException();
        }
        this.buf = buf;
        this.pos = offset;
        //count为length或buf.length-offset其中的较小者
        this.count = Math.min(offset + length, buf.length);
        this.markedPos = offset;
    }

    /** 检查流是否被关闭。若字符缓冲为null,则认为流已关闭。*/
    private void ensureOpen() throws IOException {
        if (buf == null)
            throw new IOException("Stream closed");
    }

    /**
     * 读取单个字符。
     * 如果到达缓冲区末尾,返回-1
     */
    public int read() throws IOException {
        synchronized (lock) {
            ensureOpen();
            if (pos >= count)
                return -1;
            else
                return buf[pos++];
        }
    }

    /**
     * 读取数据,并保存到字符数组b中。
     */
    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;
        }
    }

    /**
     * 判断此流是否支持mark()操作
     * CharArrayReader支持mark()操作。
     * 
     */
    public boolean markSupported() {
        return true;
    }

    /**
     * 标记流中的当前位置。
     * 对reset()的后续调用会将该流重新定位到此点。
     */
    public void mark(int readAheadLimit) throws IOException {
        synchronized (lock) {
            ensureOpen();
            markedPos = pos;
        }
    }

    /**
     * 将该流重置为最新的标记。
     * 如果从未标记过,则将其重置到开头。
     *
     * @exception  IOException  If an I/O error occurs
     */
    public void reset() throws IOException {
        synchronized (lock) {
            ensureOpen();
            pos = markedPos;
        }
    }

    /**
     * 关闭该流并释放与之关联的所有系统资源。
     */
    public void close() {
        buf = null;
    }
}
demo
import java.io.CharArrayReader;
import java.io.IOException;

import org.junit.Test;

public class CharArrayReaderTest {

    /**
     * CharArrayReader的API测试函数
     */
    @Test
    public void tesCharArrayReader() {
        try {
            CharArrayReader reader = new CharArrayReader(
                    new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' });

            // 从reader中连续读取三个字节
            for (int i = 0; i < 3; i++) {
                if (reader.ready() == true) {
                    char tmp = (char) reader.read();
                    System.out.print(tmp);
                }
            }
            System.out.println();

            // 测试是否支持mark
            if (!reader.markSupported()) {
                System.out.println("make not supported!");
                return;
            } else
                System.out.println("make supported!");

            // 标记,当前位置为d
            reader.mark(0);

            // 跳过2个字符,当前位置为f
            reader.skip(2);

            // 向下读取两个字符,fg
            char[] buf = new char[2];
            reader.read(buf, 0, 2);
            System.out.println("buf:" + String.valueOf(buf));

            // 重置当前位置为上一次标记的位置,即为d
            reader.reset();

            // 向下读取两个字符,de
            reader.read(buf, 0, 2);
            System.out.println("buf:" + String.valueOf(buf));

            // 关闭后,在调用方法,会抛出“java.io.IOException: Stream closed”异常
            reader.close();
            reader.read();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

执行方法后,控制台打印结果为:

abc
make supported!
buf:fg
buf:de
java.io.IOException: Stream closed
总结
  • CharArrayReader实现一个可用作字符输入流的字符缓冲区。
  • 在做所有操作前,都要确认流处于open状态。判断流处于open状态的依据是buf不为null。close方法中会将buf置为null。
  • CharArrayReader支持mark()操作。

CharArrayWriter

public class CharArrayWriter extends Writer {
    /**
     * 存储数据的字符缓冲区
     */
    protected char buf[];

    /**
     * 缓冲区中的字符个数
     */
    protected int count;

    /**
     * 创建一个新的CharArrayWriter。
     * 缓冲区大小默认为32
     */
    public CharArrayWriter() {
        this(32);
    }

    /**
     * 创建一个新的CharArrayWriter,指定缓冲区大小为initialSize
     * 如果initialSize为负数,抛出异常
     */
    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;
            //如果buf存满、则将buf容量扩大1倍、并将原来buf中count字符copy到新的buf中  
            if (newcount > buf.length) {
                buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
            }
            buf[count] = (char)c;
            count = newcount;
        }
    }

    /**
     * 将字符数组c中从off开始的len个字符写入到缓冲区中。
     */
    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;
            //如果buf存满、则将buf容量扩大1倍、并将原来buf中count字符copy到新的buf中 
            if (newcount > buf.length) {
                buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
            }
            System.arraycopy(c, off, buf, count, len);
            count = newcount;
        }
    }

    /**
     * 将字符串str中从索引off开始的len个字符写入到缓冲区中。
     */
    public void write(String str, int off, int len) {
        synchronized (lock) {
            int newcount = count + len;
            //如果buf存满、则将buf容量扩大1倍、并将原来buf中count字符copy到新的buf中 
            if (newcount > buf.length) {
                buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
            }
            str.getChars(off, off + len, buf, count);
            count = newcount;
        }
    }

    /**
     * 将缓冲区的内容写入另一个字符流out。
     */
    public void writeTo(Writer out) throws IOException {
        synchronized (lock) {
            out.write(buf, 0, count);
        }
    }

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

    /**
     * 将指定字符序列的子序列添加到此 writer。
     * @since  1.5
     */
    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;
    }

    /**
     * 将指定字符添加到此writer。
     * @since 1.5
     */
    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() { }

}
deom
import java.io.CharArrayWriter;
import java.io.IOException;

import org.junit.Test;

public class CharArrayWriterTest {

    private static final char[] charArr = new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g'};

    /**
     * CharArrayWriter的API测试函数
     */
    @Test
    public void testCharArrayWriter() {
        try {
            // 创建CharArrayWriter字符流,默认大小为32
            CharArrayWriter writer = new CharArrayWriter();

            writer.write('A');
            writer.write("BCDEF");
            writer.write(charArr, 1, 3);
            System.out.println("写入字符A,写入字符串BCDEF,写入charArr中从索引位置1开始的三个字符,即bcd,此时的writer为:\n" + writer);

            writer.append('0').append("12345").append(String.valueOf(charArr), 3, 6);
            System.out.println("写入字符0,写入字符串12345,写入charArr中从索引位置3到5的三个字符,即def,此时的writer为:\n" + writer);

            System.out.println("此时writer的大小为:\n" + writer.size());

            char[] buf = writer.toCharArray();
            System.out.println("将writer转化为字符数组再将其打印:\n" + String.valueOf(buf));

            // 创建CharArrayWriter字符流,指定大小为100
            CharArrayWriter writer2 = new CharArrayWriter(100);
            writer.writeTo(writer2);
            System.out.println("将writer缓冲区内容写入到wirter2中,writer缓冲区内容为:\n" + writer2);

            writer.reset();
            System.out.println("将writer重置,此时其缓冲区为:\n" + writer);

            writer2.close();
            System.out.println("将writer2关闭,调用其size方法,结果为:\n" + writer2.size());
            System.out.println("如果没有抛出异常,说明其close方法没有作用。");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

执行方法后,控制台打印内容为:

写入字符A,写入字符串BCDEF,写入charArr中从索引位置1开始的三个字符,即bcd,此时的writer为:
ABCDEFbcd
写入字符0,写入字符串12345,写入charArr中从索引位置35的三个字符,即def,此时的writer为:
ABCDEFbcd012345def
此时writer的大小为:
18
将writer转化为字符数组再将其打印:
ABCDEFbcd012345def
将writer缓冲区内容写入到wirter2中,writer缓冲区内容为:
ABCDEFbcd012345def
将writer重置,此时其缓冲区为:

将writer2关闭,调用其size方法,结果为:
18
如果没有抛出异常,说明其close方法没有作用。
总结
  • CharArrayWriter实现一个可用作字符输出流的字符缓冲区。
  • CharArrayWriter的缓冲区会随向流中写入数据而自动增长。
  • 可使用CharArrayWritert的oCharArray()和 toString()获取缓冲区中数据。
  • CharArrayWriter中close()方法无效。

关于CharArrayReader与CharArrayWriter就讲到这里,想了解更多内容请参考

版权声明
作者:潘威威

原文地址:CSDN博客-潘威威的博客-http://blog.csdn.net/panweiwei1994/article/details/78324632

本文版权归作者所有,欢迎转载。转载时请在文章明显位置给出原文作者名字(潘威威)及原文链接。请勿将本文用于任何商业用途。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值