基本概念
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() {
}