简介
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对象。