您的位置:首页 > 编程语言 > Java开发

Java IO - CharArrayReader&CharArrayWriter

2016-05-25 22:04 796 查看

基本概念

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() {
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: